package com.ray.service;

import static org.hamcrest.CoreMatchers.nullValue;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import javax.net.ssl.HttpsURLConnection;

import com.ray.bean.*;
import com.ray.mapper.CompanyMapper;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.ray.exception.ServiceException;
import com.ray.filter.HttpAspect;
import com.ray.mapper.BasicDataMapper;
import com.ray.mapper.DingTalkMapper;
import com.ray.mapper.WorkOrderMapper;
import com.ray.pojo.ApplyRepairMoneyPojo;
import com.ray.pojo.AttendApplicationDetailInfoPojo;
import com.ray.pojo.AttendDevicePojo;
import com.ray.pojo.AttendQueryDailyStatisticsPojo;
import com.ray.pojo.AttendSourceRecordPojo;
import com.ray.pojo.ClockSend;
import com.ray.pojo.MyUser;
import com.ray.pojo.UserAttendInfoPojo;
import com.ray.pojo.attend.AskForApproverPojo;
import com.ray.pojo.attend.AttendanceApprovalInfoPojo;
import com.ray.pojo.attend.AttendanceDailyInfoPojo;
import com.ray.pojo.attend.AttendanceInfoResultPojo;
import com.ray.pojo.attend.ClockTimePojo;
import com.ray.pojo.attend.FillcardApplicationPojo;
import com.ray.pojo.attend.LeaveApplicationPojo;
import com.ray.pojo.attend.OvertimeApplicationPojo;
import com.ray.pojo.attend.OvertimeRulePojo;
import com.ray.pojo.attend.SummaryBodyPojo;
import com.ray.pojo.attend.UserFinancePojo;
import com.ray.pojo.attend.UserWorkPlanPojo;
import com.ray.service.model.dorm.PersonOfDormStatisticsOut;
import com.ray.util.AttendanceUtil;
import com.ray.util.DingTalkUtil;
import com.ray.util.GUID;
import com.ray.util.RedirectUrlUtil;
import com.ray.util.TimeAndUnix;
import com.ray.util.UnicodeNativeUtils;
import com.ray.util.WeiXinParamesUtil;
import com.ray.util.callback.CallBackBody;
import com.ray.util.callback.CallBackTask;
import com.ray.util.weixin.WeixinTemplateList;
import com.ray.util.weixin.WeixinTemplateSender;
import com.sun.org.apache.bcel.internal.generic.NEW;



@Service
public class DingTalkService {
	private Logger logger = Logger.getLogger(DingTalkService.class);  
	@Autowired
	DingTalkMapper dingTalkMapper;
	@Autowired
	WeiXinService weiXinService;
	@Autowired
	WeiXinPeopleService weiXinPeopleService;
	@Autowired
	BasicDataService basicDataService;
	@Autowired
	AttendanceService attendanceService;
	@Autowired
	DormManageService dormManageService;
	@Autowired
	WorkshopService workshopService;
	@Autowired
	OrderCostGlassesService orderCostGlassesService;
	@Autowired
	WorkOrderMapper workOrderMapper;
	@Autowired
	BasicDataMapper basicDataMapper;
	@Autowired
	CompanyMapper companyMapper;
	
	/**
	 * 根据人员id与日期获取考勤信息   
	 * @param map
	 * @return  
	 * @author 王荣
	 * @throws ParseException 
	 */
	public UserAttendInfoPojo getUserAttendInfo(Map<String,Object> map) throws ParseException {
		UserAttendInfoPojo UserAttendInfoPojo = dingTalkMapper.getUserAttendInfo(map);
		List<AttendOvertimeRuleBean> attendOvertimeRuleBeans = dingTalkMapper.getOvertimeRule(map);
		AttendOvertimeRuleBean attendOvertimeRuleBean = attendOvertimeRuleBeans == null || attendOvertimeRuleBeans.size()<=0 ? null : attendOvertimeRuleBeans.get(0);
		//打卡信息
		List<Map<String, Object>> clockList = UserAttendInfoPojo.getClockList(true);
		String attendanceTime = UserAttendInfoPojo.getAttendanceTime();
		//一天应打卡次数
		if(attendanceTime!=null) {
			int clockTimes = attendanceTime.replace(" ", "-").split("-").length;
			clockList = AttendanceUtil.getClockList2(clockList, clockTimes,attendanceTime);
			UserAttendInfoPojo.setClockList(clockList);
		}
		//加班审批
		List<Map<String, Object>> overtimeApprovalList = UserAttendInfoPojo.getOvertimeApprovalList(true);
		//请假审批
		List<Map<String, Object>> leaveApprovalList = UserAttendInfoPojo.getLeaveApprovalList(true);
		//班次名称
		UserAttendInfoPojo.setDuration(AttendanceUtil.getWorkdateDuration(clockList, leaveApprovalList, overtimeApprovalList, attendOvertimeRuleBean, UserAttendInfoPojo.getClassName(), attendanceTime));
		return UserAttendInfoPojo;
	}
	/**  
	 * 获取钉钉的考勤结果信息  
	 * @param map
	 * @return  
	 * @author 王荣
	 */ 
	public Map<String,Integer> getClockResult(Map<String,Object> map) {
		ClockSend clockSend=new ClockSend();
		String startDay = (String)map.get("startDay");
		String endDay = (String)map.get("endDay");
		System.out.println("startDay:"+startDay+" endDay:"+endDay);
		String accessToken = DingTalkUtil.getAccessToken();
		//获取部门列表
//		JSONObject deptListjsonObject = DingTalkUtil.getDepartmentList();//只获得一个人？
//		JSONObject department = JSONObject.parseObject(deptListjsonObject.getString("department"));//jsonString
		JSONObject jsonObject = DingTalkUtil.getDepartmentUser(accessToken,"1");//只获得一个人？
		String jsonUser=jsonObject.getString("userlist");
		JSONArray jsonArray = JSONArray.parseArray(jsonUser);
		System.out.println("jsonArray:"+jsonArray);
		List<String> userList = new ArrayList<>();
		if(jsonArray.size()>0) {
			for(int i=0;i<jsonArray.size();i++) {
				JSONObject json=jsonArray.getJSONObject(i);
				userList.add(json.getString("userid"));
			}
		}
		clockSend.setUseridlist(userList);
		Gson gson = new Gson(); 
	    String jsonClock =gson.toJson(clockSend);
	    System.out.println("jsonClock:"+jsonClock);
	    String url ="https://oapi.dingtalk.com/attendance/list?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN", accessToken);
	    JSONObject daKaJsonObject = DingTalkUtil.httpRequest(url, "POST", jsonClock);//post参数需要json格式
	    Set<String> errorSet=new HashSet<String>();
        Set<String> allSet=new HashSet<String>();
        System.out.println("jsonObject:"+daKaJsonObject.toString());
        String jsonResult=daKaJsonObject.getString("recordresult");
		JSONArray resultArray = JSONArray.parseArray(jsonResult);
		if(resultArray!=null && resultArray.size()>0) {
			for(int i=0;i<resultArray.size();i++) {
				JSONObject json=resultArray.getJSONObject(i);
				String exception=json.getString("exception_type");
				if(!"".equals(exception)) {
					errorSet.add(json.getString("userid"));
				}
				allSet.add(json.getString("userid"));
			}
		}
	    
		Map<String,Integer> succAndErrMap=new HashMap<String,Integer>();
		succAndErrMap.put("successUserCount", allSet.size()-errorSet.size());
		succAndErrMap.put("errorUserCount", errorSet.size());
		return succAndErrMap;
	}
	/**
	 * 获取奖惩制度信息
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public List<AttendanceRewardAndPunishBean> getRewardAndPunishInfo(Map<String,Object> map) {
		return dingTalkMapper.getRewardAndPunishInfo(map);
	}
	
	public AttendanceRewardAndPunishBean getAttendanceRewardAndPunishBeanByRank(List<AttendanceRewardAndPunishBean> beans , String rank ) {
		AttendanceRewardAndPunishBean ret =null;
		for(AttendanceRewardAndPunishBean bean : beans) {
			if(rank!=null &&!"null".equals(rank) && bean.getRank() != null && Double.valueOf(bean.getRank()).equals( Double.valueOf(rank))  ) {
				ret = bean;
				break;
			}
		}
		return ret;
	}
	/**
	 * 奖惩制度设置
	 * @param map
	 * @author 王荣
	 */
	public void rewardAndPunishSet(Map<String,Object> map) {
		//查找此公司奖惩制度设定的记录数，无则插入，有则修改，有且不足则插入+修改
		List<AttendanceRewardAndPunishBean> b = dingTalkMapper.getRewardAndPunishInfo(map);
		int count = 0;
		if(b!=null && b.size()>0) {
			count = b.size();
		}
		Integer[] array1 = (Integer[])map.get("array1");//迟到早退分钟数
		Double[] array2 = (Double[])map.get("array2");//迟到早退扣款数
		Double[] array3 = (Double[])map.get("array3");//旷工扣款比例
		Double[] array4 = (Double[])map.get("array4");//请假扣款比例
		Double[] array5 = (Double[])map.get("array5");//加班工资比例
		String loginCompany = (String)map.get("loginCompany");
		int length = array1.length;
		int length3 = array3.length;
		int length4 = array4.length;
		int length5 = array5.length;
		int temp = count;
		int c = count;
		if(length>count) {
			for(;temp<length;temp++) {
				//插入奖惩记录
				AttendanceRewardAndPunishBean rewardAndPunish = new AttendanceRewardAndPunishBean();
				rewardAndPunish.setRank(temp+1);
				rewardAndPunish.setClocking(array1[temp]);
				rewardAndPunish.setClockingCharge(array2[temp]);
				if(temp<length3) {
					rewardAndPunish.setAbsent(array3[temp]);
				}
				if(temp<length4) {
					rewardAndPunish.setLeave(array4[temp]);
				}
				if(temp<length5) {
					rewardAndPunish.setOvertime(array5[temp]);
				}
				rewardAndPunish.setCompany(loginCompany);
				dingTalkMapper.insertAttendanceRewardAndPunish(rewardAndPunish);
			}
		}
		if(length<count) {
			c = length;
			//删除
			System.out.println("count-length:"+(count-length));
			int t = length;
			for(;t<count;t++) {
				AttendanceRewardAndPunishBean rewardAndPunish = new AttendanceRewardAndPunishBean();
				rewardAndPunish.setId(b.get(t).getId());
				rewardAndPunish.setCompany(loginCompany);
				dingTalkMapper.deleteRewardAndPunish(rewardAndPunish);
			}
		}
		for(int a=0;a<c;a++) {
			//修改记录
			System.out.println("test1:"+b.get(a));
			System.out.println("test2:"+b.get(a).getId());
			AttendanceRewardAndPunishBean rewardAndPunish = new AttendanceRewardAndPunishBean();
			rewardAndPunish.setId(b.get(a).getId());
			rewardAndPunish.setRank(a+1);
			rewardAndPunish.setClocking(array1[a]);
			rewardAndPunish.setClockingCharge(array2[a]);
			rewardAndPunish.setAbsent(array3[a]);
			rewardAndPunish.setLeave(array4[a]);
			rewardAndPunish.setOvertime(array5[a]);
			rewardAndPunish.setCompany(loginCompany);
			dingTalkMapper.updateAttendanceRewardAndPunish(rewardAndPunish);
		}
	}
	/**
	 * 获取加班规则考勤组名称
	 * @param groupIds
	 * @return
	 * @author 王荣
	 */
	public List<String> getGroupName(String groupIds) {
		List<String> groupNames = dingTalkMapper.getGroupName(groupIds);
		return groupNames;
	}
	/**
	 * 根据考勤组id查询考勤组信息
	 * @param id
	 * @return
	 * @author 王荣
	 */
	public List<AttendanceGroupBean> getGroupDetail(String id) {
		List<AttendanceGroupBean> groupDetail = dingTalkMapper.getGroupDetail(id);
		return groupDetail;
	}
	/**
	 * 删除考勤组
	 * @param id
	 * @author 王荣
	 */
	public void deleteGroup(String id) {
		dingTalkMapper.deleteGroup(id);
	}
	/**
	 * 修改考勤组
	 * @param map
	 * @author 王荣
	 */
	public void updateGroup(Map<String,Object> map) {
		dingTalkMapper.updateUserGroupId(map);
		dingTalkMapper.updateGroup(map);
		
		String monthlyClassArray = map.get("monthlyClassArray")==null?"[]":map.get("monthlyClassArray").toString();
		List<Map<String, Object>> monthlyClassList = DingTalkUtil.parseJsonArrayStrToList(monthlyClassArray);
		if(monthlyClassList.size()>0) {
			map.put("monthlyClassList", monthlyClassList);
			dingTalkMapper.operationAttendGroupMonthlyClass(map);
			//判断修改的月份是否为本月
			DateTime now = new DateTime();
			Date workdate = null;
			try {
				workdate = new SimpleDateFormat("yyyy-MM-dd").parse(monthlyClassList.get(0).get("workdate").toString());
			} catch (ParseException e) {
				e.printStackTrace();
			}
			//同年同月
			if(now.getYear()==new DateTime(workdate).getYear() 
					&& now.getMonthOfYear()==new DateTime(workdate).getMonthOfYear()) {
				//Timer timer = new Timer();
				/*timer.schedule(new TimerTask() {
					@Override
					public void run() {*/
						//修改本考勤组本月的每日工资明细 月初-今天
						attendanceService.updateDailySalaryRecord(now.dayOfMonth().withMinimumValue().toString("yyyy-MM-dd"), 
								now.toString("yyyy-MM-dd"), 
								map.get("loginCompany").toString(), null, Integer.valueOf(map.get("id").toString()));
					/*}
				}, 1);*/
			}
		}
	}
	/**
	 * 根据班次id查询班次名称+时间
	 * @param classId
	 * @return
	 * @author 王荣
	 */
	public String selectClassById(String classId) {
		return dingTalkMapper.selectClassById(classId);
	}
	/**
	 * 根据部门id查询部门人数
	 * @param deptId
	 * @return
	 * @author 王荣
	 */
	public int selectCountById(String deptId) {
		return dingTalkMapper.selectCountById(deptId);
	}
	/**
	 * 查询考勤组
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<AttendanceGroupBean> queryGroup(Map<String,Object> map) {
		int count=0;
		DatatablesViewPageBean<AttendanceGroupBean> dtcpb=new DatatablesViewPageBean<AttendanceGroupBean>();
		count=dingTalkMapper.queryGroupCount(map);
		dtcpb.setReturnData(count>0?dingTalkMapper.queryGroup(map):new ArrayList<>());
		dtcpb.setiTotalDisplayRecords(count);
		dtcpb.setiTotalRecords(count);
		return dtcpb;
	}
	/**
	 * 添加考勤组
	 * @param map
	 * @author 王荣
	 */
	public void insertGroup(Map<String,Object> map) {
		dingTalkMapper.insertGroup(map);
	}
	/**
	 * 修改班次
	 * @param attendanceClass
	 * @author 王荣
	 */
	public void updateClass(AttendanceClassBean attendanceClass) {
		dingTalkMapper.updateClass(attendanceClass);
	}
	/**
	 * 获取班次名称，用于校验班次名称是否重复
	 * @param myuser
	 * @return
	 * @author 王荣
	 */
	public List<String> queryClassName(MyUser myuser) {
		String company = myuser.getCompany();
		return dingTalkMapper.queryClassName(company);
	}
	/**
	 * 根据部门查询对应员工
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<PersonBean> getPersonName(Map<String,Object> map) {
		int count=0;
		DatatablesViewPageBean<PersonBean> dtcpb=new DatatablesViewPageBean<PersonBean>();
		count=dingTalkMapper.getPersonNameCount(map);
		dtcpb.setReturnData(count>0?dingTalkMapper.getPersonName(map):new ArrayList<>());
		dtcpb.setiTotalDisplayRecords(count);
		dtcpb.setiTotalRecords(count);
		return dtcpb;
	}
	/**
	 * 查询部门
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<DepartmentBean> queryDept(Map<String,Object> map) {
		int count=0;
		DatatablesViewPageBean<DepartmentBean> dtcpb=new DatatablesViewPageBean<DepartmentBean>();
		count=dingTalkMapper.queryDeptCount(map);
		dtcpb.setReturnData(count>0?dingTalkMapper.queryDept(map):new ArrayList<>());
		dtcpb.setiTotalDisplayRecords(count);
		dtcpb.setiTotalRecords(count);
		return dtcpb;
	}
	/**
	 * 查询班次
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<AttendanceClassBean> queryClass(Map<String,Object> map) {
		int count=0;
		DatatablesViewPageBean<AttendanceClassBean> dtcpb=new DatatablesViewPageBean<AttendanceClassBean>();
		count=dingTalkMapper.queryClassCount(map);
		dtcpb.setReturnData(count>0?dingTalkMapper.queryClass(map):new ArrayList<>());
		dtcpb.setiTotalDisplayRecords(count);
		dtcpb.setiTotalRecords(count);
		return dtcpb;
	}
	/**
	 * 插入班次
	 * @param attendanceClass
	 * @param myuser
	 * @author 王荣
	 */
	public void insertClass(AttendanceClassBean attendanceClass,MyUser myuser) {
		attendanceClass.setCompany(myuser.getCompany());
		dingTalkMapper.insertClass(attendanceClass);
	}
	/**
	 * 删除班次
	 * @param myuser
	 * @param id
	 * @author 王荣
	 */
	public void deleteClass(MyUser myuser, String id) {
		String company = myuser.getCompany();
		dingTalkMapper.deleteClass(company,id);
	}
	/**
	 * 查询原始记录
	 * @param map
	 * @return
	 * @throws ServiceException
	 * @author 王荣
	 */
	public DatatablesViewPageBean<AttendSourceRecordPojo> queryAttendance(Map<String,Object> map) throws ServiceException {
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		int count=0;
		DatatablesViewPageBean<AttendSourceRecordPojo> dtcpb=new DatatablesViewPageBean<AttendSourceRecordPojo>();
		count=dingTalkMapper.queryAttendanceCount(map);
		dtcpb.setReturnData(count>0?dingTalkMapper.queryAttendance(map):new ArrayList<AttendSourceRecordPojo>());
		dtcpb.setiTotalDisplayRecords(count);
		dtcpb.setiTotalRecords(count);
		return dtcpb;
	}
	/**
	 * 查询原始记录无效打卡记录
	 * @param map
	 * @return
	 * @throws ServiceException
	 * @author 王荣
	 */
	public DatatablesViewPageBean<AttendSourceRecordPojo> queryAttendanceInvalid(Map<String,Object> map) throws ServiceException {
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		int count=0;
		DatatablesViewPageBean<AttendSourceRecordPojo> dtcpb=new DatatablesViewPageBean<AttendSourceRecordPojo>();
		count=dingTalkMapper.queryAttendanceInvalidCount(map);
		dtcpb.setReturnData(count>0?dingTalkMapper.queryAttendanceInvalid(map):new ArrayList<AttendSourceRecordPojo>());
		dtcpb.setiTotalDisplayRecords(count);
		dtcpb.setiTotalRecords(count);
		return dtcpb;
	}
	/**
	 * httpGet
	 * @param url
	 * @return
	 * @throws Exception
	 * @author 王荣
	 */
	public static JSONObject httpGet(String url) throws Exception {
		//1.创建httpClient 
		CloseableHttpClient httpClient = HttpClients.createDefault();
		//2.生成一个请求
		HttpGet httpGet = new HttpGet(url);
		//3.配置请求的属性
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();
		httpGet.setConfig(requestConfig);
        
		//4.发起请求，获取响应信息
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpGet, new BasicHttpContext());

			//如果返回结果的code不等于200，说明出错了  
			if (response.getStatusLine().getStatusCode() != 200) {

				System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
						+ ", url=" + url);
				return null;
			}
			//5.解析请求结果
			HttpEntity entity = response.getEntity();      //reponse返回的数据在entity中 
			if (entity != null) {
				String resultStr = EntityUtils.toString(entity, "utf-8");  //将数据转化为string格式  

				JSONObject result = JSON.parseObject(resultStr);    //将String转换为 JSONObject
				if (result.getInteger("errcode") == 0) {
					return result;
				} else {
					System.out.println("request url=" + url + ",return value=");
					System.out.println(resultStr);
					int errCode = result.getInteger("errcode");
					String errMsg = result.getString("errmsg");
					throw new Exception("error code:"+errCode+", error message:"+errMsg); 
				}
			}
		} catch (IOException e) {
			System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
			e.printStackTrace();
		} finally {
			if (response != null) try {
				response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return null;
	}
	/**
     * 获取钉钉的accessToken
     */
    public static String getAccessToken(String url,String corpid,String secret){
        String requestUrl = url + "?corpid="+corpid+"&corpsecret="+secret;
        String result = doGet(requestUrl);
        String accessToken = null;
        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
        jsonObject = JSON.parseObject(result);
        String msg = (String)jsonObject.get("errmsg");
        if("ok".equals(msg)){
            accessToken = (String)jsonObject.get("access_token");
        }
        return accessToken;
    }
    /**
     * 获取钉钉打卡记录
     * @param accessToken
     * @param workDateFrom
     * @param workDateTo
     * @return
     * @author 王荣
     */
    public static JSONArray getCardList(String accessToken, String workDateFrom, String workDateTo){
        String recordUrl = "https://oapi.dingtalk.com/attendance/list?access_token="+accessToken;
        JSONObject jsonObject = new JSONObject();
        System.out.println("workDateFrom:"+workDateFrom+" AndWorkDateTo:"+workDateTo);
        jsonObject.put("workDateFrom",workDateFrom);
        jsonObject.put("workDateTo",workDateTo);
        String result = doPost(recordUrl,jsonObject,"utf-8");
        com.alibaba.fastjson.JSONObject resultJSON = com.alibaba.fastjson.JSONObject.parseObject(result);
        String msg = (String)resultJSON.get("errmsg");
        System.out.println("message:"+msg);
        JSONArray jsonArray = null;
        if("ok".equals(msg)){
            jsonArray = (JSONArray) resultJSON.get("recordresult");
        }
        return jsonArray;
    }
    /**
     * doPost
     * @param url
     * @param jsonObject
     * @param charset
     * @author 王荣
     */
    public static String doPost(String url, JSONObject jsonObject, String charset){
    	CloseableHttpClient httpClient = null;
        HttpPost httpPost = null;
        String result = null;
        try{
        	httpClient = HttpClients.createDefault();
            httpPost = new HttpPost(url);
            //设置参数
            StringEntity entity = new StringEntity(jsonObject.toString(),charset);
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            HttpResponse response = httpClient.execute(httpPost);
            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity resEntity = response.getEntity();
                if(resEntity != null){
                    result = EntityUtils.toString(resEntity,charset);
                }
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }
        return result;
    }
    /**
     * doGet
     * @param url
     * @author 王荣
     */
    public static String doGet(String url){
        String result = null;
        HttpGet request = new HttpGet(url);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpResponse response = httpClient.execute(request);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                result= EntityUtils.toString(response.getEntity(),"utf-8");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
	/**  
	 * 获取补卡审批人员（该职员所属部门的部门经理） 
	 * @param map
	 * @return List<PersonBean>
	 * @author 王荣
	 */ 
	public List<PersonBean> getFillCardApprover(Map<String,Object> map) {
		return dingTalkMapper.getFillCardApprover(map);
	}
	
	/**  
	 * 提交请假单  
	 * @param map  
	 * @return 生成请假单的id
	 * @author 王荣
	 * @throws Exception 
	 */ 
	@SuppressWarnings({ "unchecked"})
	public String submitLeaveApplication(Map<String,Object> map) throws ParseException {
		Gson gson = new Gson();
		AttendApprovalLeaveBean attendApprovalLeaveBean = gson.fromJson((String) map.get("data"), AttendApprovalLeaveBean.class);
		Long id = attendApprovalLeaveBean.getId();
		String type = attendApprovalLeaveBean.getType();
		String startTime = attendApprovalLeaveBean.getStartTime();
		String endTime = attendApprovalLeaveBean.getEndTime();
		String reason = attendApprovalLeaveBean.getReasonText();
		List<String> auditorList = attendApprovalLeaveBean.getAuditorList();
		map.put("id", id);
		map.put("type", type);
		map.put("startTime", startTime);
		map.put("endTime", endTime);
		map.put("reason", reason);
		map.put("auditorList", auditorList);
		//生成请假审批编号
		String approvalNo = dingTalkMapper.getApprovalNo("QJ");
		map.put("approvalNo", approvalNo);
		UserWorkPlanPojo workplan = dingTalkMapper.getUserWorkingPlan(map);
		Integer groupId = workplan.getGroupId();
		Assert.isTrue(groupId!=null,"未设置考勤组，请先设置");
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		List<Map<String, Object>> workdateList = workplan.getWorkdateList();
		Date d1 = sdf.parse(startTime);//定义起始日期
		Date d2 = sdf.parse(endTime);//定义结束日期
		Calendar calendar = Calendar.getInstance();//定义日期实例
		calendar.setTime(d1);//设置日期起始时间
		long duration = 0;//请假时长
		long start = 0;
		long end = d2.getTime();
		boolean flag = true;//是否第一天的标识
		List<Map<String,Object>> m = dingTalkMapper.checkForTimeOverlap(map);
		if(m!=null && m.size()>0) {
			String mStartTime = m.get(0).get("startTime").toString();
			String mEndTime = m.get(0).get("endTime").toString();
			Assert.isTrue(false,mStartTime+"至"+mEndTime+"期间已存在请假，并且时间重叠，请重新选择请假时间或撤销重复请假单");
		}
		List<Map<String,Object>> checkOvertimeRepeatList = dingTalkMapper.checkOvertimeRepeat(map);
		Assert.isTrue(checkOvertimeRepeatList==null || checkOvertimeRepeatList.size()<=0,"请假范围与已有加班审批时间重叠");
		for(int index=0;index<workdateList.size();index++) {
			Map<String, Object> workdateMap = workdateList.get(index);
			String workdate = workdateMap.get("workdate").toString();
			Integer classId = (Integer)workdateMap.get("classId");
			if(classId!=null) {//上班
				Object restStart = workdateMap.get("restStart");
				Object restEnd = workdateMap.get("restEnd");
				boolean isNeedRest = workdateMap.get("isNeedRest")==null?false:(boolean) workdateMap.get("isNeedRest");
				List<String> clockList = (List<String>) workdateMap.get("clockList");
				List<Map<String,Long>> planList = new ArrayList<Map<String,Long>>();
				Map<String,Long> slMap = null;
				if(clockList.size()==2 && isNeedRest) {//当一次上下班打卡并有休息时
					slMap = new HashMap<String,Long>();
					slMap.put("start", sdf.parse(workdate+" "+clockList.get(0)+":00").getTime());
					slMap.put("end", sdf.parse(workdate+" "+restStart+":00").getTime());
					planList.add(slMap);
					slMap = new HashMap<String,Long>();
					slMap.put("start", sdf.parse(workdate+" "+restEnd+":00").getTime());
					slMap.put("end", sdf.parse(workdate+" "+clockList.get(1)+":00").getTime());
					planList.add(slMap);
				}else {
					for(int i=0;i<clockList.size();i++) {
						String clockStr = workdate+" "+clockList.get(i)+":00";
						if(i%2==0) {
							slMap = new HashMap<String,Long>();
							slMap.put("start", sdf.parse(clockStr).getTime());
						}else {
							slMap.put("end", sdf.parse(clockStr).getTime());
							planList.add(slMap);
						}
					}
				}
				
				if(flag) {
					start = d1.getTime();
				}else {
					start = planList.get(0).get("start");//第二天开始赋值为第一个上班时间
				}
				//计算一天的请假时长
				for(int i = 0,l = planList.size();i<l;i++) {
					long startValue = planList.get(i).get("start");
					long endValue = planList.get(i).get("end");
					if(end<=startValue || start>=endValue) {//在范围外时跳出
						continue;
					}
					if(start<=startValue && end<=endValue) {
						duration += end-startValue;
					}else if(start<=startValue && end>=endValue) {
						duration += endValue-startValue;
					}else if(start>=startValue && end<=endValue) {
						duration += end-start;
					}else if(start>=startValue && end>=endValue) {
						duration += endValue-start;
					}
				}
			}
			flag = false;
	 	}
		//时长保留两位小数,四舍五入
		BigDecimal bg = new BigDecimal((double)duration/(1000*60*60)).setScale(2, BigDecimal.ROUND_HALF_UP);
		double durationValue = (double)bg.doubleValue();
		Assert.isTrue(durationValue>0,"时长不能为0，请检查当天是否休息");
		map.put("duration", (double)bg.doubleValue());
		map.put("copyPersonList", attendApprovalLeaveBean.getCopyPersonList());
		String firstApproverId = auditorList.get(0);
		String content = "请假时间从 "+startTime+" 至 "+endTime;
		String loginUserName = map.get("loginUserName").toString();
		String loginUserPhone = map.get("loginUserPhone").toString();
		dingTalkMapper.submitLeaveApplication(map);//提交请假单 会在map中返回添加的记录的id
		String pageType = RedirectUrlUtil.ATTEND_LEAVE_APPROVAL_DETAIL_URL+map.get("id").toString();
		//发送消息  异步执行
		sendWatiApprovalTips(firstApproverId, "1",loginUserName, loginUserPhone, content, reason,pageType);
		/*Object context = "上下文信息";
		new CallBackTask(new CallBackBody() {
            @Override
			public void execute(Object context) throws Exception {
                System.out.println("\n正在执行耗时操作...");
                
        		sendWatiApprovalTips(firstApproverId, "1",loginUserName, loginUserPhone, content, reason,pageType);
                System.out.println("\n执行完成！");
            }
            public void onSuccess(Object context) {
                System.out.println("\n成功后的回调函数...");
            }
            public void onFailure(Object context) {
                System.out.println("\n失败后的回调函数...");
            }
        }).start(context);*/
		return id.toString();
	}
	
	
	/**  
	 * 获取可审核人 type为空或没有设置时 获取所有人为审核人
	 * @param map
	 * @return List<AskForApproverPojo>
	 * @author 王荣
	 */ 
	public List<AskForApproverPojo> askForApprover(Map<String,Object> map) {
		return dingTalkMapper.askForApprover(map);
	}
	/**  
	 * 查询审批人流程设置
	 * @param map
	 * @return DatatablesViewPageBean<AttendApprovalProcessBean>
	 * @author 王荣
	 */ 
	public DatatablesViewPageBean<AttendApprovalProcessBean> queryApprovalProcessSet(Map<String,Object> map) {
		int count = 0;
		DatatablesViewPageBean<AttendApprovalProcessBean> dvpb = new DatatablesViewPageBean<AttendApprovalProcessBean>();
		count = dingTalkMapper.queryApprovalProcessSetCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.queryApprovalProcessSet(map):new ArrayList<AttendApprovalProcessBean>());
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	/**  
	 * 审批人设置 attend_approval_process_set
	 * @param map  
	 * @author 王荣
	 */ 
	@SuppressWarnings("unchecked")
	public void addAndDeleteApprovalProcess(Map<String,Object> map) {
		String addArray = map.get("addArray").toString();
		String subArray = map.get("subArray").toString();
		net.sf.json.JSONArray jsonArray1 = net.sf.json.JSONArray.fromObject(addArray);
		net.sf.json.JSONArray jsonArray2 = net.sf.json.JSONArray.fromObject(subArray);
		List<Integer> addList=jsonArray1.subList(0, jsonArray1.size());
		List<Integer> subList=jsonArray2.subList(0, jsonArray2.size());
		map.put("addList", addList);
		map.put("subList", subList);
		dingTalkMapper.addAndDeleteApprovalProcess(map);
	}
	/**  
	 * 删除考勤审批流程设置（审核人）
	 * @param map  
	 * @author 王荣
	 */ 
	public void deleteApprovalProcessSet(Map<String,Object> map) {
		dingTalkMapper.deleteApprovalProcessSet(map);
	}
	/**  
	 * 获取请假审批信息
	 * @param map
	 * @return List<AttendApprovalLeaveBean>
	 * @author 王荣
	 */ 
	public List<AttendApprovalLeaveBean> getApprovalProcessInfo(Map<String,Object> map) {
		return dingTalkMapper.getApprovalProcessInfo(map);
	}
	/**  
	 * 操作考勤审批单 请假、补卡
	 * @param map  
	 * @author 王荣
	 */ 
	public void updateAttendApproval(Map<String,Object> map) {
		dingTalkMapper.updateAttendApproval(map);
		String approvalType = map.get("approvalType").toString();
		String status = map.get("status").toString();
		String id = map.get("id").toString();
		String approverId = map.get("approverId").toString();//表示下一审核人的id
		if("2".equals(approvalType) && "1".equals(status) && "".equals(approverId)) {//表示同意补卡，添加打卡数据
			//补卡  打卡记录的id
			long guid = GUID.getGuid();
			map.put("guid", guid);
			dingTalkMapper.insertFillcardRecord(map);
			//根据审批单id，将打卡记录id保存到补卡审批记录clock_id
			dingTalkMapper.saveFillcardClockId(map);
		}
		if("2".equals(approvalType) && "3".equals(status)) {
			//补卡撤销时，根据补卡审批记录的clock_id删除对应的打卡记录
			dingTalkMapper.deleteClockRecordByClockId(map);
		}
		String flowId = map.get("flowId").toString();//当前审批流程的id
		String loginUserName = map.get("loginUserName").toString();
		String reason = map.get("reason").toString();
		
		/*new CallBackTask(new CallBackBody() {
            @Override
			public void execute(Object context) throws Exception {*/
                AttendanceApprovalInfoPojo approvalBean = null;
                if("2".equals(approvalType)) {//补卡信息
                	approvalBean = dingTalkMapper.getFillcardApprovalDetail(id);
                }else {
                	approvalBean = dingTalkMapper.getLeaveApprovalDetail(id);
                }
                String createrId = String.valueOf(approvalBean.getCreaterId());//发起人的id
                String createrName = approvalBean.getCreaterName();//发起人的姓名
                String approvalTypeStr = null;
                String pageType = null;
        		switch(approvalType) {
        		case "1":approvalTypeStr = "请假审批";pageType = RedirectUrlUtil.ATTEND_LEAVE_APPROVAL_DETAIL_URL+id;break;
        		case "2":approvalTypeStr = "补卡审批";pageType = RedirectUrlUtil.ATTEND_FILLCARD_APPROVAL_DETAIL_URL+id;break;
        		default:approvalTypeStr = "申请";
        		}
                //同意或转交 
        		if(status.equals("1") || status.equals("4")) {
        			//表示需要下一个审核人
        			if(approverId!=null && !"".equals(approverId)) {
        				String createrPhone = approvalBean.getPhoneNumber();
        				//发送待审核任务提醒
        				sendWatiApprovalTips(approverId, approvalType,createrName, createrPhone, reason, "",pageType);
        			}else {//表示审批完成
        				//重新计算每日工资
        				attendanceService.updateDailySalaryRecord(approvalBean.getStartTime(), approvalBean.getEndTime(), approvalBean.getCompany(), approvalBean.getCreaterId());
        				//审批流程
        				List<Map<String,Object>> processList = approvalBean.getProcessList();
        				String approverName = "";//协助人的姓名
        				if(processList!=null && processList.size()>0) {
        					for(Map<String,Object> a :processList) {
        						approverName+=a.get("approverName")+"，";
        					}
        				}
        				approverName = approverName.substring(0, approverName.length()-1);
        				//发送申请批复通知至（发起人、抄送人）
        				sendApplyStatusTips("您的"+approvalTypeStr+"已处理，请知晓",createrId,status,approverName,pageType);
        				List<Map<String,Object>> copyforList = approvalBean.getCopyforList();
        				if(copyforList!=null && copyforList.size()>0) {
        					for(Map<String,Object> i:copyforList) {
        						sendApplyStatusTips(createrName+"的"+approvalTypeStr+"已处理，请知晓",i.get("copyforId").toString(),status,approverName,pageType);
        					}
        				}
        			}
        		}else if(status.equals("2")) {//拒绝
        			//发送申请批复通知消息至（发起人、之前的审批人）
    				sendApplyStatusTips("您的"+approvalTypeStr+"已处理，请知晓",createrId,status,loginUserName,pageType);
    				List<Map<String,Object>> processList = approvalBean.getProcessList();
    				if(processList!=null && processList.size()>0) {
    					flag:for(Map<String,Object> a :processList) {
    						if(a.get("processId")!=null&&flowId.equals(a.get("processId").toString())) {
    							break flag;
    						}
    						sendApplyStatusTips(createrName+"的"+approvalTypeStr+"已处理，请知晓",a.get("approverId").toString(),status,loginUserName,pageType);
    					}
    				}
        		}else if(status.equals("3")) {//撤销
        			//重新计算每日工资
        			attendanceService.updateDailySalaryRecord(approvalBean.getStartTime(), approvalBean.getEndTime(), approvalBean.getCompany(), approvalBean.getCreaterId());
        			//发送申请批复通知消息至之前的审批人
        			List<Map<String,Object>> processList = approvalBean.getProcessList();
    				if(processList!=null && processList.size()>0) {
    					flag:for(Map<String,Object> a :processList) {
    						if(a.get("status")!=null&&!a.get("status").equals("3")) {
    							sendApplyStatusTips(loginUserName+"的"+approvalTypeStr+"已处理，请知晓",a.get("approverId").toString(),status,loginUserName,pageType);
    						}
    						if(a.get("processId")!=null&&flowId.equals(a.get("processId").toString())) {
    							break flag;
    						}
    					}
    				}
        		}
           // }
        //}).start("");
	}
	/**
	 * 审批结果通知  
	 * @param first 小标题：张三员工您好，您的请假申请已批复
	 * @param receiverId 接收人用户id
	 * @param status 审批单状态
	 * @param approverName 审批人姓名
	 * @param dealwithTime 处理时间
	 * @param remarks 备注
	 * @author 王荣
	 */
	public void sendApplyStatusTips(String first, String receiverId,String status, String approverName,String pageType) {
		String statusString = "";
		switch(status) {
		case "1":statusString = "已同意";break;
		case "2":statusString = "已拒绝";break;
		case "3":statusString = "已撤销";break;
		case "4":statusString = "已转交";break;
		}
		List<String> openIdList = weiXinPeopleService.getOpenIdByUserId(receiverId);
		Assert.isTrue(openIdList!=null && openIdList.size()>0, "发送审批结果通知消息失败，请确认接受人是否绑定微信");
		String openId = openIdList.get(0);
		com.alibaba.fastjson.JSONObject data = WeixinTemplateList.packJsonApprovalResult(first, approverName, statusString, "点击查看详情", null, null, null, null);
		String accessToken=weiXinService.getAccessToken(null); 
		WeixinTemplateSender.sendWechatmsgToUser(openId, WeiXinParamesUtil.approvalResultTemplateID, WeiXinParamesUtil.messageLink+"?loginToken="+openId+"&pageType="+pageType, data, accessToken);
	}
	/**
	 * 发送待审核任务提醒  
	 * @param openId 接收人微信openid
	 * @param firstApproverId 接收人用户id 没有用，为了区分重载方法
	 * @param type 审批类型 1：请假、2：补卡、3：加班
	 * @param createrName 审批单提交人姓名
	 * @param phone 提交人手机号
	 * @param content 内容
	 * @param remarks 备注
	 * @param pageType 跳转页面
	 * @author 王荣
	 */
	/*public void sendWatiApprovalTips(String openId,String firstApproverId,String type,String createrName,String phone,String content,String remarks,String pageType) {
		Assert.isTrue(openId!=null, "提交成功，但是发送消息至审核人失败，请确认审核人是否绑定微信");
		switch(type) {
		case "1":type="请假";break;
		case "2":type="补卡";break;
		case "3":type="加班";break;
		}
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		com.alibaba.fastjson.JSONObject data = WeixinTemplateList.packJsonWatiApproval("您好！您有新的待审核任务", type, createrName, phone, sdf.format(new Date()),content,remarks, null, null, null, null, null,null,null);
		String accessToken=weiXinService.getAccessToken(null); 
		WeixinTemplateSender.sendWechatmsgToUser(openId, WeiXinParamesUtil.watiApprovalTemplateID, WeiXinParamesUtil.messageLink+"?loginToken="+openId+"&pageType="+pageType, data, accessToken);
	}*/
	/**
	 * 发送待审核信息
	 * @param firstApproverId 接收人用户id
	 * @param type 审批类型 1：请假、2：补卡、3：加班
	 * @param createrName 审批单提交人姓名
	 * @param phone 提交人手机号
	 * @param content 内容
	 * @param remarks 备注
	 * @param pageType 跳转页面
	 * @author 王荣
	 */
	public void sendWatiApprovalTips(String firstApproverId,String type,String createrName,String phone,String content,String remarks,String pageType) {
		List<String> openIdList = weiXinPeopleService.getOpenIdByUserId(firstApproverId);
		Assert.isTrue(openIdList!=null && openIdList.size()>0, "提交成功，但是发送消息至审核人失败，请确认审核人是否绑定微信");
		String openId = openIdList.get(0);
		switch(type) {
		case "1":type="请假";break;
		case "2":type="补卡";break;
		case "3":type="加班";break;
		case "4":type="报销";break;
		case "5":type="行政处罚";break;
		case "6":type="行政奖励";break;
		}
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		com.alibaba.fastjson.JSONObject data = WeixinTemplateList.packJsonWatiApproval("您好！您有新的待审核任务", type, createrName, phone, sdf.format(new Date()),content,remarks, null, null, null, null, null,null,null);
		String accessToken=weiXinService.getAccessToken(null); 
		WeixinTemplateSender.sendWechatmsgToUser(openId, WeiXinParamesUtil.watiApprovalTemplateID, WeiXinParamesUtil.messageLink+"?loginToken="+openId+"&pageType="+pageType, data, accessToken);
	}
	/**  
	 * 获取请假审批单信息
	 * @param map
	 * @return AttendApprovalLeaveBean
	 * @author 王荣
	 */ 
	public AttendApprovalLeaveBean getApprovalInfoById(Map<String,Object> map) {
		return dingTalkMapper.getApprovalInfoById(map);
	}
	/**  
	 * 修改职员工资明细
	 * @param map
	 * @author 王荣
	 */ 
	public void updateFinanceDetail(Map<String,Object> map) {
		dingTalkMapper.updateFinanceDetail(map);
	}
	/**  
	 * 获取奖惩制度设定信息
	 * @param map
	 * @return  
	 * @author 王荣
	 */ 
	public List<Map<String,String>> selectRewardAndPunishInfo(Map<String,Object> map) {
		return dingTalkMapper.selectRewardAndPunishInfo(map);
	}
	
	//获取个人电费水费信息，因为查询出来的人数和排序不同，所以转为map，再根据用户信息key值查询
	public Map<String, PersonOfDormStatisticsOut> getPersonElectricAndWaterInfo(String startTime, String endTime, String company){
		List<PersonOfDormStatisticsOut> personOfDormStatisticsOuts = dormManageService.getPersonOfDormStatistics(startTime,endTime,company);
		Map<String, PersonOfDormStatisticsOut> personElectricAndWaterMap = new HashMap<>();
		if(personOfDormStatisticsOuts!=null && personOfDormStatisticsOuts.size()>0) {
			//转list为map
			for(PersonOfDormStatisticsOut personOfDormStatisticsOut : personOfDormStatisticsOuts) {
				//用userName做key值
				personElectricAndWaterMap.put(personOfDormStatisticsOut.getUsername(), personOfDormStatisticsOut);
			}
		}
		return personElectricAndWaterMap;
	}
	
	//个人计件工资，因为查询出来的人数和排序不同，所以转为map，再根据用户信息key值查询
	@SuppressWarnings("unchecked")
	public Map<String, TableData> getPieceWageInfo(Map<String,Object> map){
		Map<String, Object> personDataMap = workshopService.getPersonData(map);
		List<TableData> noProcedure = (List<TableData>) personDataMap.get("noProcedure");
		Map<String, TableData> pieceWageMap = new HashMap<>();
		if(noProcedure!=null && noProcedure.size()>0) {
			for(TableData tableDate : noProcedure) {
				//用userName做key值
				pieceWageMap.put(tableDate.getName(), tableDate);
			}
		}
		//获取维修计件工资
		List<TableData> actualSalaryTableData = workOrderMapper.getActualSalaryByWorkCompeleteTime(map);
		for(TableData tableData : actualSalaryTableData) {
			//用userName做key值
			pieceWageMap.put(tableData.getName(), tableData);
		}
		return pieceWageMap;
	}
	
	//补料扣款，因为查询出来的人数和排序不同，所以转为map，再根据用户信息key值查询
	public Map<Integer, Double> getApplyRepairMoneyInfo(String startDate,String endDate,String companyName){
		List<ApplyRepairMoneyPojo> applyRepairMoneyPojos = orderCostGlassesService.getApplyRepairOrderMoney(startDate, endDate, null, companyName);
		Map<Integer, Double> applyRepairMoneyMap = new HashMap<>();
		for(ApplyRepairMoneyPojo applyRepairMoneyPojo : applyRepairMoneyPojos) {
			applyRepairMoneyMap.put(applyRepairMoneyPojo.getUserId(), applyRepairMoneyPojo.getAllMoney());
		}
		return applyRepairMoneyMap;
	}
	
	/**
	 * 查询月度汇总信息 
	 * @param requestMap
	 * @return
	 * @throws ParseException
	 * @author 王荣
	 */
	public DatatablesViewPageBean<SummaryBodyPojo> querySummaryBody(Map<String,Object> requestMap) throws ParseException {
		//如果为空则设为"[]"
		requestMap.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(requestMap.computeIfAbsent("deptIds", k -> "[]").toString()));
		requestMap.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(requestMap.computeIfAbsent("workshopIds", k -> "[]").toString()));
		requestMap.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(requestMap.computeIfAbsent("userIds", k -> "[]").toString()));
        int count = dingTalkMapper.queryClockTimeCount(requestMap);
        DatatablesViewPageBean<SummaryBodyPojo> dvpb = new DatatablesViewPageBean<SummaryBodyPojo>();
        dvpb.setiTotalDisplayRecords(count);
        dvpb.setiTotalRecords(count);
		if(count<=0) {
			dvpb.setReturnData(new ArrayList<SummaryBodyPojo>());
			return dvpb;
		}
		//要返回的数据
		List<SummaryBodyPojo> returnList = new ArrayList<SummaryBodyPojo>();
		//查询开始结束日期大于今日时，设为今日日期
		if(new SimpleDateFormat("yyyy-MM-dd").parse(requestMap.get("endDate").toString()).getTime() > new Date().getTime()) requestMap.put("endDate", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
		if(new SimpleDateFormat("yyyy-MM-dd").parse(requestMap.get("startDate").toString()).getTime() > new Date().getTime()) requestMap.put("startDate", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
		//汇总信息
		List<AttendanceInfoResultPojo> attendanceInfoResultPojos = attendanceService.getAttendanceInfo(requestMap);
		//用户考勤工资明细
		List<UserFinancePojo> userFinancePojos = dingTalkMapper.getUserFinanceDetail(requestMap);
		//水电费用
		Map<String, PersonOfDormStatisticsOut> personElectricAndWaterMap = getPersonElectricAndWaterInfo(
				requestMap.get("startDate").toString(), 
				new DateTime(new SimpleDateFormat("yyyy-MM-dd").parse(requestMap.get("endDate").toString())).plusDays(1).toString("yyyy-MM-dd"), 
				requestMap.get("loginCompany").toString());
		//计件工资
		requestMap.put("startDay", requestMap.get("startDate"));
		requestMap.put("date", requestMap.get("endDate"));
		requestMap.put("workShop", "");
		Map<String, TableData> pieceWageMap = getPieceWageInfo(requestMap);
		//补料扣款
		Map<Integer, Double> applyRepairMoneyMap = getApplyRepairMoneyInfo(requestMap.get("startDate").toString(), requestMap.get("endDate").toString(), requestMap.get("loginCompany").toString());
		//遍历每个人的考勤统计信息
		for(int index = 0;index<attendanceInfoResultPojos.size();index++) {
			//个人考勤统计信息
			AttendanceInfoResultPojo attendanceInfoResultPojo = attendanceInfoResultPojos.get(index);
			//要返回的个人考勤月度统计信息
			returnList.add(getPersonAttendanceInfo(attendanceInfoResultPojo, 
					userFinancePojos.get(index), //个人考勤工资设置
					personElectricAndWaterMap.get(attendanceInfoResultPojo.getUserName()), //个人水电费信息
					pieceWageMap, 
					applyRepairMoneyMap));
		}
		dvpb.setReturnData(returnList);
		return dvpb;
	}
	
	/**
	 * 获取个人考勤月度统计信息
	 * @param attendanceInfoResultPojo
	 * @param userFinancePojo
	 * @param personElectricAndWater
	 * @param pieceWageMap
	 * @param applyRepairMoneyMap
	 * @return
	 * @author 王荣
	 */
	public SummaryBodyPojo getPersonAttendanceInfo(AttendanceInfoResultPojo attendanceInfoResultPojo,
			UserFinancePojo userFinancePojo,
			PersonOfDormStatisticsOut personElectricAndWater,
			Map<String, TableData> pieceWageMap,
			Map<Integer, Double> applyRepairMoneyMap
			) {
		
		Integer userId = attendanceInfoResultPojo.getUserId();
		String workerNo = attendanceInfoResultPojo.getWorkerNo();
		String userName = attendanceInfoResultPojo.getUserName();
		String deptName = attendanceInfoResultPojo.getDeptName();
		String groupName = attendanceInfoResultPojo.getGroupName();
		String method = attendanceInfoResultPojo.getMethod();
		String workshopName = attendanceInfoResultPojo.getWorkshopName();
		Double attendanceSalary = attendanceInfoResultPojo.getAttendanceSalary();
		/** 迟到扣款	 */
		double lateDeductions = attendanceInfoResultPojo.getLateDeductions();
		/** 早退扣款 */
		double earlyDeductions = attendanceInfoResultPojo.getEarlyDeductions();
		/**旷工扣款*/
		double absentDeductions = attendanceInfoResultPojo.getAbsentDeductions();
		/**请假扣款 */
		double leaveDeductions = attendanceInfoResultPojo.getLeaveDeductions();
		/**加班工资 */
		double overtimeSalary = attendanceInfoResultPojo.getOvertimeSalary();
		/*月薪*/
		double mothlySalary = attendanceInfoResultPojo.getMonthlySalary();
		
		//要返回的个人月度考勤统计信息
		SummaryBodyPojo summaryBodyPojo = new SummaryBodyPojo(userId, userName, deptName, groupName, method , workerNo);
		summaryBodyPojo.setWorkshopName(workshopName);
		double socialSecurity = userFinancePojo.getSocialSecurity(),//社保
				accumulationFund = userFinancePojo.getAccumulationFund(),//公积金
				otherAddition = userFinancePojo.getOtherAddition(),//其他加项
				otherDeduction = userFinancePojo.getOtherDeductions();//其他减项
		//电费
		double personElectricFee = personElectricAndWater==null ? 0 : personElectricAndWater.getElectricFee().doubleValue();
		//水费
		double personWaterFee = personElectricAndWater==null ? 0 : personElectricAndWater.getWaterFee().doubleValue();
		//计件工资
		double pieceWage = pieceWageMap.get(userName)==null ? 0 : pieceWageMap.get(userName).getSumPrice();
		//补料扣款
		double applyRepairMoney = applyRepairMoneyMap.get(userId)==null ? 0 : applyRepairMoneyMap.get(userId);
		//考勤每日信息
		List<AttendanceDailyInfoPojo> attendanceDailyInfoPojos = attendanceInfoResultPojo.getAttendanceDailyInfoList();
		attendanceDailyInfoPojos = attendanceDailyInfoPojos==null ? new ArrayList<>() : attendanceDailyInfoPojos;
		double earlyDuration = 0,//早退时长
				lateDuration = 0,//迟到时长
				effectiveWorkTime = 0,//有效工作时长
				leaveDuration = 0,//请假时长
				overtimeDuration = 0;//加班时长
		List<Map<String, Object>> workdateList = new ArrayList<>();
		//遍历每日考勤信息
		for(AttendanceDailyInfoPojo attendanceDailyInfoPojo : attendanceDailyInfoPojos) {
			String className = attendanceDailyInfoPojo.getClassName();
			String attendanceTime = attendanceDailyInfoPojo.getAttendanceTime();
			String[] attendanceTimeArr = attendanceTime==null?new String[0]:attendanceTime.replace(" ", "-").split("-");
			//一天应打卡次数
			int clockTimes = attendanceTimeArr.length;
			//每日日期与工作状态
			Map<String, Object> workdateMap = new HashMap<>();
			workdateMap.put("workdate", attendanceDailyInfoPojo.getWorkdate());
			//暂存工作状态
			Map<Integer, String> stateMap = new HashMap<>();
			List<Map<String, Object>> lateInfoList = attendanceDailyInfoPojo.getLateInfoList();
			for(Map<String, Object> lateInfo : lateInfoList) {
				lateDuration += Long.parseLong(lateInfo.get("duration").toString());
				stateMap.put(Integer.valueOf(lateInfo.get("index").toString()), "迟到");
			}
			List<Map<String, Object>> earlyInfoList = attendanceDailyInfoPojo.getEarlyInfoList();
			for(Map<String, Object> earlyInfo : earlyInfoList) {
				earlyDuration += Long.parseLong(earlyInfo.get("duration").toString());
				stateMap.put(Integer.valueOf(earlyInfo.get("index").toString()), "早退");
			}
			List<Map<String, Object>> lackInfoList = attendanceDailyInfoPojo.getLackInfoList();
			for(Map<String, Object> lackInfo : lackInfoList) {
				stateMap.put(Integer.valueOf(lackInfo.get("index").toString()), "缺卡");
			}
			//有效工作时长
			List<Map<String, Object>> effectiveTimeInfoList = attendanceDailyInfoPojo.getEffectiveTimeInfoList();
			for(Map<String, Object> effectiveTimeInfo : effectiveTimeInfoList) {
				effectiveWorkTime += Long.parseLong(effectiveTimeInfo.get("duration").toString());
			}
			//请假
			List<Map<String, Object>> leaveInfoList = attendanceDailyInfoPojo.getLeaveInfoList();
			//加班
			List<Map<String, Object>> overtimeInfoList = attendanceDailyInfoPojo.getOvertimeInfoList();
			for(Map<String, Object> overtimeInfo : overtimeInfoList) {
				//bug 修改加班时间 不满半小时 不算
				//Long.parseLong(overtimeInfo.get("duration").toString()) 
				overtimeDuration += Long.parseLong(overtimeInfo.get("duration").toString())/Long.parseLong(30*60*1000+"")*Long.parseLong(30*60*1000+"");
			}
			String text = "";
			int state = 0;
			if(groupName==null) {
				text = "不在考勤组";
			}else {
				if(className!=null) {
					if(lateInfoList.size()==0 && earlyInfoList.size()==0 && lackInfoList.size()==0 && leaveInfoList.size()==0) {
						text = "正常";
						state = 1;
					}else if(clockTimes>0 && clockTimes==lackInfoList.size()) {
						text = "旷工";
					}else {
						for(Integer key : stateMap.keySet()) {
							switch((key+1)%2){
							case 1:
								text += "上班"+(int)Math.ceil((double)(key+1)/2);
								break;
							case 0:
								text += "下班"+(int)Math.ceil((double)(key+1)/2);
							}
							text += stateMap.get(key)+"\r\n";
						}
					}
				}else {
					if(overtimeInfoList.size()>0) {
						text = "休息并打卡";state = 1;
					}else {
						text = "休息";state = 1;
					}
				}
				for(Map<String, Object> leaveInfo : leaveInfoList) {
					leaveDuration += Long.parseLong(leaveInfo.get("duration").toString());
				}
			}
			workdateMap.put("text", text);
			workdateMap.put("state", state);
			workdateList.add(workdateMap);
		}
		double realSalary = 0;
		pieceWage = pieceWage - lateDeductions - earlyDeductions - absentDeductions;
		if("按月".equals(method)) {
			realSalary = attendanceSalary;
			pieceWage = 0;
		}else if("计件".equals(method)) {//计件工资需要扣除迟到早退旷工 不扣除请假
			realSalary = pieceWage;
			attendanceSalary = 0.0;
		}else {//保底加计件 计件工资>出勤工资 则用计件工资计算
			realSalary = pieceWage > attendanceSalary ? pieceWage : attendanceSalary;
		}
		//以半小时为单位计算，不足的不计算例如：加班1.82小时=1.5小时
		overtimeDuration = overtimeDuration-overtimeDuration%(30*60*1000);
		//实际薪水
		realSalary = AttendanceUtil.getRealSalary(realSalary, otherAddition, socialSecurity,accumulationFund,otherDeduction,personElectricFee,personWaterFee,applyRepairMoney);
		summaryBodyPojo.setWorkdateList(workdateList);
		summaryBodyPojo.setLeaveList(attendanceInfoResultPojo.getLeaveList());
		summaryBodyPojo.setEarlyDuration(earlyDuration);
		summaryBodyPojo.setLateDuration(lateDuration);
		summaryBodyPojo.setLeaveDuration(leaveDuration);
		//summaryBodyPojo.setWorkTimeDuration(effectiveWorkTime+overtimeDuration);
		summaryBodyPojo.setWorkTimeDuration(effectiveWorkTime);
		summaryBodyPojo.setWorkOvertimeDuration(overtimeDuration);
		summaryBodyPojo.setSocialSecurity(socialSecurity);//社保
		summaryBodyPojo.setAccumulationFund(accumulationFund);//公积金
		summaryBodyPojo.setOtherAddition(otherAddition);//其他加项
		summaryBodyPojo.setOtherDeduction(otherDeduction);//其他扣款
		summaryBodyPojo.setAttendanceSalary(attendanceSalary);//出勤工资
		summaryBodyPojo.setPieceWage(pieceWage);//计件工资
		summaryBodyPojo.setElectricFee(personElectricFee);//电费
		summaryBodyPojo.setWaterFee(personWaterFee);//水费
		summaryBodyPojo.setApplyRepairMoney(applyRepairMoney);//补料扣款		
		summaryBodyPojo.setRealSalary(realSalary);//实发工资
		
		//计算该月的奖罚 20190920
		for(AttendanceDailyInfoPojo attendanceDailyInfoPojo : attendanceDailyInfoPojos) {
			if(attendanceDailyInfoPojo.getWorkdate()==null) {
				break;
			}
			//获取年月 201905 
			String workdate = attendanceDailyInfoPojo.getWorkdate().substring(0,7).replace("-", "");
			//计算这个月奖罚
			Double award= dingTalkMapper.getViewAdministrativePenalty(userId,workdate,6);
			Double punish= dingTalkMapper.getViewAdministrativePenalty(userId,workdate,5);
			summaryBodyPojo.setAdministrativePenaltyForAward((award!=null)?award:0);
			summaryBodyPojo.setAdministrativePenaltyForPunish((punish!=null)?punish:0);
			realSalary=realSalary+summaryBodyPojo.getAdministrativePenaltyForAward()-summaryBodyPojo.getAdministrativePenaltyForPunish();
			summaryBodyPojo.setRealSalary(realSalary);//实发工资
			break;
		}
		return summaryBodyPojo;
	}
	
	/**
	 * 获取可选参与人员的信息  
	 * @param map
	 * @return  List<Map>
	 * @author 王荣
	 */
	public List<Map<String,String>> getParticipantInfo(Map<String,String> map){
		return dingTalkMapper.getParticipantInfo(map);
	}
	/**
	 * 添加考勤补卡审批记录
	 * @param map
	 * @author 王荣
	 */
	public String insertAttendApprovalFillcard(Map<String,Object> map) {
		Gson gson = new Gson();
		AttendApprovalFillcardBean attendApprovalFillcardBean = gson.fromJson((String) map.get("data"), AttendApprovalFillcardBean.class);
		String reason = attendApprovalFillcardBean.getReason();
		List<String> auditorList = attendApprovalFillcardBean.getAuditorList();
		List<String> copyPersonList = attendApprovalFillcardBean.getCopyPersonList();
		map.put("id", attendApprovalFillcardBean.getId());
		map.put("approvalNo", dingTalkMapper.getApprovalNo("BK"));
		map.put("reason", reason);
		map.put("classId", attendApprovalFillcardBean.getClassId());
		map.put("auditorList", auditorList);
		map.put("copyPersonList", copyPersonList);
		map.put("baseCheckTime", attendApprovalFillcardBean.getBaseCheckTime());
		List<Map<String,Object>> isRepaeatList = dingTalkMapper.checkAttendApprovalFillcardRepeat(map);
		
		Assert.isTrue(!(isRepaeatList!=null && isRepaeatList.size()>0),"该时间点已有补卡申请单，如要添加请先撤销");
		dingTalkMapper.insertAttendApprovalFillcard(map);
		
		String firstApproverId = auditorList.get(0);
		String loginUserName = map.get("loginUserName").toString();
		String loginUserPhone = map.get("loginUserPhone").toString();
		String pageType = RedirectUrlUtil.ATTEND_FILLCARD_APPROVAL_DETAIL_URL+map.get("id");
		sendWatiApprovalTips(firstApproverId, "2",loginUserName, loginUserPhone, "", reason,pageType);
		//发送消息  异步执行
		Object context = "上下文信息";
		/*new CallBackTask(new CallBackBody() {
            @Override
			public void execute(Object context) throws Exception {
                System.out.println("\n正在执行耗时操作...");
                
        		sendWatiApprovalTips(firstApproverId, "2",loginUserName, loginUserPhone, "", reason,pageType);
                System.out.println("\n执行完成！");
            }
            public void onSuccess(Object context) {
                System.out.println("\n成功后的回调函数...");
            }
            public void onFailure(Object context) {
                System.out.println("\n失败后的回调函数...");
            }
        }).start(context);*/
		return map.get("id").toString();
	}
	/**
	 * 获取与我相关的审批记录
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<Map<String,Object>> getMyApprovalList(Map<String,Object> map){
		int count = 0;
		DatatablesViewPageBean<Map<String,Object>> dvpb = new DatatablesViewPageBean<Map<String,Object>>();
		count = dingTalkMapper.getMyApprovalListCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.getMyApprovalList(map):new ArrayList<Map<String,Object>>());
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	/**
	 * 获取审批单详情
	 * @param map
	 * @return AttendApplicationDetailInfoPojo
	 * @author 王荣
	 */
	public AttendApplicationDetailInfoPojo getApplicationDetailInfo(Map<String,Object> map){
		return dingTalkMapper.getApplicationDetailInfo(map);
	}
	/**
	 * 发送打卡成功提醒
	 * @param userId
	 * @param userCheckTime
	 * @author 王荣
	 */
	public void sendClockMessage(Map<String,Object> map) {
		String accessToken=weiXinService.getAccessToken(null); 
		Assert.isTrue(accessToken!=null, "获取accessToken失败");
		String userCheckTime = map.get("userCheckTime")==null?"":map.get("userCheckTime").toString();
		String guid = map.get("guid")==null?"":map.get("guid").toString();
		map = dingTalkMapper.getUserNameAndOpenIdByUserId(map);
		Object open = map.get("openId");
		String userName = map.get("userName")==null?null:map.get("userName").toString();
		if(open!=null && !open.equals("")) {
			String openId = open.toString();
	    	
	    	String resultMsg= "打卡成功";
	    	if(guid !=null && !"".equals(guid)) {//必须有guid 避免其他数据干扰
	    		/**
				 * 判断打卡时间是否是有效范围
				 */
				SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		    	Calendar calendar = Calendar.getInstance();
		    	calendar.add(Calendar.DATE, -1);
	    		Map<String, Object> invalidClockTime = new HashMap<>();
		    	invalidClockTime.put("clockStartTime", df.format(calendar.getTime()));//昨天
		    	invalidClockTime.put("clockEndTime", df.format(new Date()));//今天
		    	invalidClockTime.put("guid", guid);
		    	List<Map<String, Object>> list = dingTalkMapper.getInvalidClockTime(invalidClockTime);
	    		if(list.size()>0) {//存在无效数据
	    			String base_check_start_time =list.get(0).get("base_check_start_time").toString();
		    		String base_check_end_time = list.get(0).get("base_check_end_time").toString();
		    		Date date;
		    		Date date2;
					try {
						date = new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(base_check_start_time);
						base_check_start_time = new SimpleDateFormat("HH:mm").format(date);
						date2 = new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(base_check_end_time); 
						base_check_end_time = new SimpleDateFormat("HH:mm").format(date2);
					} catch (ParseException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 
		    		resultMsg= "打卡无效 打卡有效时间范围:"+base_check_start_time+"-"+base_check_end_time;
	    		}
	    	}
			
			com.alibaba.fastjson.JSONObject data = WeixinTemplateList.packJsonToCheckWork("考勤打卡", userName, "", userCheckTime,resultMsg , null, null, null, null, null);
			String message = WeixinTemplateSender.sendWechatmsgToUser(openId, "X7ZQo8XNaQf_qS63eV1R6oqXeo1GSXBXSU6w0pS9esI", null, data, accessToken);
			if("success".equals(message)) {
				message = userName+"消息发送成功";
			}else {
				message = userName+"消息发送异常："+message;
			}
		}else {
			System.out.println("sendClockMessage:"+userName+"消息发送失败，reason：用户没有绑定微信");
		}
		
		//拿着guid查询到考勤机的基础体温和本人的体温
    	List<Map<String, Object>> deviceManagerList =  dingTalkMapper.getDeviceByGuid(guid,map.get("company").toString());
    	//如果超过基础体温则通知考勤机管理人
    	for(Map<String, Object> deviceManager : deviceManagerList) {
    		//打卡人的体温
    		String dkTemperature = deviceManager.get("temperature")!=null?deviceManager.get("temperature").toString():"0";
    		//打卡设备标准体温
    		String temperatureBasic = deviceManager.get("temperatureBasic")!=null?deviceManager.get("temperatureBasic").toString():"0";
    		//管理人的openId
    		String managerOpenId = deviceManager.get("openid")!=null?deviceManager.get("openid").toString():"";
    		
    		//打卡设备的codeName
    		String codeName = deviceManager.get("codeName")!=null?deviceManager.get("codeName").toString():"";
    		//打卡设备的codeId
    		String codeId = deviceManager.get("codeId")!=null?deviceManager.get("codeId").toString():"";
    		//打卡设备的codeArea
    		String codeArea = deviceManager.get("codeArea")!=null?deviceManager.get("codeArea").toString():"";
    		/*如果体温高于标准值 ,并且有管理人员微信  则通知管理人员*/
    		if(!"".equals(managerOpenId) && Double.valueOf(dkTemperature).compareTo(Double.valueOf(temperatureBasic))>0) {
    			String msg = "体温:"+dkTemperature+" 高于阀值 "+temperatureBasic +"请及时处理";
    			com.alibaba.fastjson.JSONObject data = WeixinTemplateList.packJsonToCheckWork("考勤打卡异常提醒", "异常人员("+userName+")", "", userCheckTime,msg , null, null, null, null, "#f00");
    			String message = WeixinTemplateSender.sendWechatmsgToUser(managerOpenId, "X7ZQo8XNaQf_qS63eV1R6oqXeo1GSXBXSU6w0pS9esI", null, data, accessToken);
    			if("success".equals(message)) {
    				message = userName+"消息发送成功";
    			}else {
    				message = userName+"消息发送异常："+message;
    			}
    		}
    		/*有地区码*/
    		if(!"".equals(codeName)) {
    			String userPhone = map.get("userPhone").toString();
    			String userIdCard = map.get("userIdCard").toString();
    			String localCodeMsg = sendlocalCode(userName,userPhone,userIdCard, codeName, codeId, codeArea);
    			System.out.println(localCodeMsg);
    			JSONObject strRet = JSONObject.parseObject(localCodeMsg);
    			if(strRet.get("success")!=null&&!"1".equals(strRet.get("success").toString()) ) {//不正常
        			com.alibaba.fastjson.JSONObject data = WeixinTemplateList.packJsonToCheckWork("地方码异常:"+codeName, "异常人员("+userName+")", "", userCheckTime,strRet.get("msg").toString() , null, null, null, null, "#f00");
        			String message = WeixinTemplateSender.sendWechatmsgToUser(managerOpenId, "X7ZQo8XNaQf_qS63eV1R6oqXeo1GSXBXSU6w0pS9esI", null, data, accessToken);
        			if("success".equals(message)) {
        				message = userName+"消息发送成功";
        			}else {
        				message = userName+"消息发送异常："+message;
        			}
    			}
    		}
    	}
	}
	/*发送地区码*/
	public String sendlocalCode(String userName, String userPhone, String userIdCard , String codeName , String codeId , String codeArea) {
		if(codeName.equals("瑞安码")) {
			return sendLocalCodeForRuian(userName, userPhone, userIdCard, codeName, codeId, codeArea);
		}
		return "没有相应的地区码";
	}
	
	public String sendLocalCodeForRuian(String userName, String userPhone, String userIdCard , String codeName , String codeId , String codeArea) {
		
		try {
			String retMsg =  WeixinTemplateSender.httpRequest(
					"http://dx.raga.gov.cn:8921/mst/api/check.jsp?t=1583368597886"
					+ "&sfzh="+userIdCard
					+ "&xm="+URLEncoder.encode(userName, "UTF-8")//+UnicodeNativeUtils.ChangeGB2NCR("沈世冠")
					+ "&sjh=15257086961"
					+ "&cph="
					+ "&kkid=2238"
					+ "&kkmc="+URLEncoder.encode(codeArea, "UTF-8")
					+ "&cr=0",
					"GET", null);
			logger.info(retMsg);
			return retMsg;
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "";
	}
	
	/**
	 * 查询每日统计
	 * @param map
	 * @return
	 * @author 王荣
	 * @throws ParseException 
	 */
	public DatatablesViewPageBean<AttendQueryDailyStatisticsPojo> queryDailyStatistics(Map<String,Object> map) throws ParseException{
		int count = 0;
		DatatablesViewPageBean<AttendQueryDailyStatisticsPojo> dvpb = new DatatablesViewPageBean<AttendQueryDailyStatisticsPojo>();
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		count = dingTalkMapper.queryDailyStatisticsCount(map);
		if(count<=0) {
			dvpb.setReturnData(new ArrayList<AttendQueryDailyStatisticsPojo>());
			dvpb.setiTotalDisplayRecords(count);
			dvpb.setiTotalRecords(count);
			return dvpb;
		}
		List<AttendQueryDailyStatisticsPojo> dailyStatisticsPojos = dingTalkMapper.queryDailyStatistics(map);
		for(AttendQueryDailyStatisticsPojo dailyStatisticsPojo : dailyStatisticsPojos) {
			AttendOvertimeRuleBean overtimeRuleBean = dailyStatisticsPojo.getOvertimeRule();
			List<Map<String, Object>> clockList = AttendanceUtil.convertProperty2Timestamp(dailyStatisticsPojo.getClockList(), new String[] {"baseCheckTime","userCheckTime"});
			List<Map<String, Object>> leaveApprovalList = AttendanceUtil.convertProperty2Timestamp(dailyStatisticsPojo.getLeaveList(), new String[] {"startTime","endTime"});
			List<Map<String, Object>> overtimeApprovalList = AttendanceUtil.convertProperty2Timestamp(dailyStatisticsPojo.getOvertimeApprovalList(), new String[] {"startTime","endTime"});
			dailyStatisticsPojo.setDuration(AttendanceUtil.getWorkdateDuration(clockList, leaveApprovalList, overtimeApprovalList, overtimeRuleBean, dailyStatisticsPojo.getClassName(), dailyStatisticsPojo.getAttendanceTime()));
		}
		dvpb.setReturnData(dailyStatisticsPojos);
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	/**
	 * 查询考勤设备信息
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<AttendDevicePojo> queryAttendDevice(Map<String,Object> map){
		int count = 0;
		DatatablesViewPageBean<AttendDevicePojo> dvpb = new DatatablesViewPageBean<AttendDevicePojo>();
		count = dingTalkMapper.queryAttendDeviceCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.queryAttendDevice(map):new ArrayList<AttendDevicePojo>());
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	/**
	 * 添加考勤机
	 * @param map
	 * @author 王荣
	 */
	public void insertAttendDevice(Map<String,Object> map) {
		List<Map<String,Object>> list = dingTalkMapper.checkAttendDeviceRepeat(map);
		Assert.isTrue(list==null || list.size()<=0,"设备编号或设备名称已存在");
		dingTalkMapper.insertAttendDevice(map);
	}
	/**
	 * 删除考勤机
	 * @param map
	 * @author 王荣
	 */
	public void deleteAttendDevice(Map<String,Object> map) {
		dingTalkMapper.deleteAttendDevice(map);
	}
	/**
	 * 修改考勤机名称
	 * @param map
	 * @author 王荣
	 */
	public void updateAttendDevice(Map<String,Object> map) {
		List<Map<String,Object>> list = dingTalkMapper.checkAttendDeviceRepeat(map);
		Assert.isTrue(list==null || list.size()<=0,"设备编号或设备名称已存在");
		dingTalkMapper.updateAttendDevice(map);
	}
	/**
	 * 获取考勤机列表
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public List<AttendDevicePojo> getAttendDevice(Map<String,Object> map){
		return dingTalkMapper.getAttendDevice(map);
	}
	/**
	 * 批量添加考勤机操作指令，添加或删除人员
	 * @param deviceIdList 设备id集合
	 * @param userId 用户id
	 * @param userName 用户姓名
	 * @author 王荣
	 */
	public void insertDeviceTrans(List<Integer> deviceIdList,String userId,String userName) {
		//数据库中已存在的deviceId
		List<Integer> deviceList = dingTalkMapper.selectAttendDeviceUserList(userId);
		List<AttendDeviceTransBean> list = new ArrayList<AttendDeviceTransBean>();
		AttendDeviceTransBean bean;
		for (Integer deviceId:deviceIdList) {//添加
			if(!deviceList.contains(deviceId)) {
				bean = new AttendDeviceTransBean(deviceId, userId, userName, "USER");
				list.add(bean);
			}
		}
		for (int deviceId:deviceList) {//删除
			if(!deviceIdList.contains(deviceId)) {
				bean = new AttendDeviceTransBean(deviceId, userId);
				list.add(bean);
			}
		}
		if(list.size()>0) {
			dingTalkMapper.deleteAttendDeviceUser(list);
			dingTalkMapper.insertAttendDeviceUser(list);
			dingTalkMapper.batchInsertDeviceCmd(list);
		}
		
	}
	/**
	 * 当禁用用户时，删除所有考勤机中的该用户
	 * @param userId 禁用的用户id
	 * @author 王荣
	 */
	public void insertDeviceTrans(String userId) {
		//数据库中已存在的deviceId
		List<Integer> deviceList = dingTalkMapper.selectAttendDeviceUserList(userId);
		List<AttendDeviceTransBean> list = new ArrayList<AttendDeviceTransBean>();
		AttendDeviceTransBean bean;
		for (int deviceId:deviceList) {//删除
			bean = new AttendDeviceTransBean(deviceId, userId);
			list.add(bean);
		}
		if(list.size()>0) {
			dingTalkMapper.deleteAttendDeviceUser(list);
			dingTalkMapper.batchInsertDeviceCmd(list);
		}
		
	}
	/**
	 * 获取考勤机中已存在的用户
	 * @param map
	 * @author 王荣
	 */
	public List<Map<String,Object>> getAttendDeviceUsers(Map<String,Object> map){
		return dingTalkMapper.getAttendDeviceUsers(map);
	}
	/**
	 * 修改设备管理员
	 * @param map
	 * @author 王荣
	 */
	public void insertAndDeleteAttendDeviceManager(Map<String, Object> map) {
		String deviceManagerArr = map.get("deviceManagerArr").toString();
		net.sf.json.JSONArray jsonArray = net.sf.json.JSONArray.fromObject(deviceManagerArr);
		/**
		 * 这里不能用sublist，使用会导致mybatis无法解析jsonArray类型异常
		 */
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < jsonArray.size(); i++){
            net.sf.json.JSONObject jsonObject = jsonArray.getJSONObject(i);
            Map<String, Object> newMap = new HashMap<String, Object>();
            for (Iterator<?> iter = jsonObject.keys(); iter.hasNext();)
            {
                String key = (String) iter.next();
                Object value = jsonObject.get(key);
                newMap.put(key, value);
            }
            list.add(newMap);
        }
		List<Map<String,Object>> managerList = dingTalkMapper.getDeviceManager(map);
		List<Map<String,Object>> cmdList = new ArrayList<Map<String,Object>>();
		for (Map<String,Object> m : list) {
			boolean flag = true;
			String managerId = m.get("managerId").toString();
			StringBuffer bodyBuf=new StringBuffer();
		    bodyBuf.append("T\0\0\0{\"user_id\":\"");
			bodyBuf.append(managerId); 
			bodyBuf.append("\",\"user_name\":\"");
			bodyBuf.append(m.get("managerName").toString());
			for(Map<String,Object> n : managerList) {
				if(managerId.equals(n.get("managerId").toString())) {
					flag = false;
				}
			}
			if(flag) {
				//修改为管理员
				bodyBuf.append("\",\"user_privilege\":\"MANAGER\"}\0");//MANAGER
				System.out.println("bufferStr:"+bodyBuf.toString());
				byte[] cmdParam = null;
				try {
					cmdParam = bodyBuf.toString().getBytes("UTF-8");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				m.put("guid", GUID.getGuid());
				m.put("cmdCode", 35);
				m.put("cmdParam", cmdParam);
				cmdList.add(m);
			}
		}
		for(Map<String,Object> m : managerList) {
			boolean flag = true;
			String managerId = m.get("managerId").toString();
			StringBuffer bodyBuf=new StringBuffer();
		    bodyBuf.append("T\0\0\0{\"user_id\":\"");
			bodyBuf.append(managerId); 
			bodyBuf.append("\",\"user_name\":\"");
			bodyBuf.append(m.get("managerName").toString());
			for(Map<String,Object> n : list) {
				if(managerId.equals(n.get("managerId").toString())) {
					flag = false;
				}
			}
			if(flag) {
				//修改为普通用户
				bodyBuf.append("\",\"user_privilege\":\"USER\"}\0");//MANAGER
				System.out.println("bufferStr:"+bodyBuf.toString());
				byte[] cmdParam = null;
				try {
					cmdParam = bodyBuf.toString().getBytes("UTF-8");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				m.put("guid", GUID.getGuid());
				m.put("cmdParam", cmdParam);
				m.put("cmdCode", 35);
				cmdList.add(m);
			}
		}
		map.put("deviceManagerList", list);
		map.put("cmdList", cmdList);
		dingTalkMapper.deleteAttendDeviceManager(map);
		dingTalkMapper.insertAttendDeviceManager(map);
		dingTalkMapper.insertAttendDeviceManagerCmd(map);
	};
	/**
	 * 查询请假审批记录
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<LeaveApplicationPojo> queryLeaveApplicationRecord(Map<String, Object> map){
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		int count = 0;
		DatatablesViewPageBean<LeaveApplicationPojo> dvpb = new DatatablesViewPageBean<LeaveApplicationPojo>();
		count = dingTalkMapper.queryLeaveApplicationRecordCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.queryLeaveApplicationRecord(map):new ArrayList<LeaveApplicationPojo>());
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	/**
	 * 查询补卡审批记录
	 * @param map
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<FillcardApplicationPojo> queryFillcardApplicationRecord(Map<String, Object> map){
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		int count = 0;
		DatatablesViewPageBean<FillcardApplicationPojo> dvpb = new DatatablesViewPageBean<FillcardApplicationPojo>();
		count = dingTalkMapper.queryFillcardApplicationRecordCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.queryFillcardApplicationRecord(map):new ArrayList<FillcardApplicationPojo>());
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	
	/**
	 * 查询加班审批记录
	 * @param map
	 * @author 王荣
	 */
	public DatatablesViewPageBean<OvertimeApplicationPojo> queryOvertimeApplicationRecord(Map<String, Object> map){
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		int count = 0;
		DatatablesViewPageBean<OvertimeApplicationPojo> dvpb = new DatatablesViewPageBean<OvertimeApplicationPojo>();
		count = dingTalkMapper.queryOvertimeApplicationRecordCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.queryOvertimeApplicationRecord(map):new ArrayList<OvertimeApplicationPojo>());
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	
	/**
	 * 查看打卡时间
	 * @param map
	 * @author 王荣
	 */
	public DatatablesViewPageBean<ClockTimePojo> queryClockTime(Map<String, Object> map){
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		int count = 0;
		DatatablesViewPageBean<ClockTimePojo> dvpb = new DatatablesViewPageBean<ClockTimePojo>();
		count = dingTalkMapper.queryClockTimeCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.queryClockTime(map):new ArrayList<ClockTimePojo>());
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	/**
	 * 获取考勤组按月排班
	 * @param requestMap
	 * @author 王荣
	 */
	public List<com.ray.pojo.attend.GroupMonthlyPlanPojo> getGroupMonthlyPlan(Map<String, Object> requestMap) {
		return dingTalkMapper.getGroupMonthlyPlan(requestMap);
	}
	/**
	 * 保存考勤加班规则
	 * @param requestParam
	 * @author 王荣
	 */
	public void saveAttendOvertimeRule(Map<String, Object> requestParam) {
		List<Map<String, Object>> repeatList = dingTalkMapper.checkOvertimeRuleNameRepeat(requestParam);
		Assert.isTrue(repeatList==null || repeatList.size()<=0,"加班规则名称重复");
		dingTalkMapper.saveAttendOvertimeRule(requestParam);
	}
	/**
	 * 查询考勤加班规则
	 * @param requestParam
	 * @return
	 * @author 王荣
	 */
	public DatatablesViewPageBean<OvertimeRulePojo> queryAttendOvertimeRule(Map<String, Object> requestParam){
		int count = 0;
		DatatablesViewPageBean<OvertimeRulePojo> dvpb = new DatatablesViewPageBean<OvertimeRulePojo>();
		count = dingTalkMapper.queryAttendOvertimeRuleCount(requestParam);
		List<OvertimeRulePojo> returnData = count>0?dingTalkMapper.queryAttendOvertimeRule(requestParam):new ArrayList<OvertimeRulePojo>();
		dvpb.setReturnData(returnData);
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	/**
	 * 删除考勤加班规则
	 * @param requestParam
	 * @author 王荣
	 */
	public void deleteAttendOvertimeRule(Map<String, Object> requestParam) {
		dingTalkMapper.deleteAttendOvertimeRule(requestParam);
	}
	/**
	 * 修改考勤加班规则
	 * @param requestParam
	 * @author 王荣
	 */
	public void updateAttendOvertimeRule(Map<String, Object> requestParam) {
		List<Map<String, Object>> repeatList = dingTalkMapper.checkOvertimeRuleNameRepeat(requestParam);
		Assert.isTrue(repeatList==null || repeatList.size()<=0,"加班规则名称重复");
		dingTalkMapper.updateAttendOvertimeRule(requestParam);
	}
	/**
	 * 保存加班审批单
	 * @param bean
	 * @author 王荣
	 * @return 
	 */
	public String saveOvertimeApplication(Map<String, Object> requestParam) {
		Gson gson = new Gson();
		//map转对象
		AttendApprovalOvertimeBean bean = gson.fromJson((String) requestParam.get("data"), AttendApprovalOvertimeBean.class);
		Integer userId = Integer.valueOf(requestParam.get("loginUserId").toString());
		String company = requestParam.get("loginCompany").toString();
		String openId = requestParam.get("loginUserOpenId")==null?null:requestParam.get("loginUserOpenId").toString();
		String phone = requestParam.get("loginUserPhone")==null?"":requestParam.get("loginUserPhone").toString();
		String createrName = requestParam.get("loginUserName").toString();
		bean.setCompany(company);
		bean.setCreaterId(userId);
		//加班开始结束时间
		String startTimeStr = bean.getStartTime();
		String endTimeStr = bean.getEndTime();
		//检查加班时间范围是否有重叠
		Map<String, Object> checkRepeatMap = new HashMap<String,Object>();
		checkRepeatMap.put("loginUserId", userId);
		checkRepeatMap.put("startTime", startTimeStr);
		checkRepeatMap.put("endTime", endTimeStr);
		List<Map<String,Object>> checkOvertimeRepeatList = dingTalkMapper.checkOvertimeRepeat(checkRepeatMap);
		Assert.isTrue(checkOvertimeRepeatList==null || checkOvertimeRepeatList.size()<=0,"加班范围与已有加班审批时间重叠");
		List<Map<String,Object>> checkForTimeOverlapList = dingTalkMapper.checkForTimeOverlap(checkRepeatMap);
		Assert.isTrue(checkForTimeOverlapList==null || checkForTimeOverlapList.size()<=0,"加班范围与已有请假时间重叠");
		//工作排班信息
		com.ray.pojo.attend.UserWorkPlanPojo workSchedulePojo = dingTalkMapper.getUserWorkSchedule(checkRepeatMap);
		if(workSchedulePojo!=null) {
			List<Map<String, Object>> workdateList = workSchedulePojo.getWorkdateList();
			for(Map<String, Object> workdateMap : workdateList) {
				if(workdateMap.get("classId")==null) {
					continue;
				}
				//日期
				String workdate = workdateMap.get("workdate").toString();
				@SuppressWarnings("unchecked")
				//打卡信息
				List<String> clockList = (List<String>) workdateMap.get("clockList");
				for(int i=1;i<clockList.size();i=i+2) {
					String baseCheckTime1 = workdate+" "+clockList.get(i-1)+":00";
					String baseCheckTime2 = workdate+" "+clockList.get(i)+":00";
					if((TimeAndUnix.compareDate(baseCheckTime1, startTimeStr)>=0 && TimeAndUnix.compareDate(startTimeStr, baseCheckTime2)>0)
							|| (TimeAndUnix.compareDate(baseCheckTime1,endTimeStr)>=0 && TimeAndUnix.compareDate(endTimeStr, baseCheckTime2)>0)
							|| (TimeAndUnix.compareDate(startTimeStr,baseCheckTime1)>=0 && TimeAndUnix.compareDate(baseCheckTime2,endTimeStr)>=0) ) {
						Assert.isTrue(true,"加班范围不能与正常工作时间重叠");
					}
				}
			}
		}
		//审批编号
		String approvalNo = dingTalkMapper.getApprovalNo("JB");
		bean.setApprovalNo(approvalNo);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		DateTime startTime = null;
		DateTime endTime = null;
		try {
			startTime = new DateTime(sdf.parse(startTimeStr));
			endTime = new DateTime(sdf.parse(endTimeStr));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		double duration = TimeAndUnix.compareDateWithHour(startTime, endTime);
		bean.setDuration(duration);
		String firstApproverId = bean.getAuditorList().get(0);
		Long id = bean.getId();
		String reason = bean.getReason();
		String content = "加班时间从"+startTimeStr+"到"+endTimeStr;
		//添加加班审批记录
		dingTalkMapper.saveOvertimeApplication(bean);
		//审批消息点击跳转页面链接
		String pageType = RedirectUrlUtil.ATTEND_OVERTIME_APPROVAL_DETAIL_URL+id;
		//异步发送待审核信息，提高响应速度，优化用户体验
		/*Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				sendWatiApprovalTips(openId,firstApproverId, "3",createrName, phone, content, reason,pageType);
			}
		}, 100);*/
		sendWatiApprovalTips(firstApproverId, "3",createrName, phone, content, reason,pageType);
		return id.toString();
	}
	/**
	 * 操作加班审批单
	 * @param map
	 * @author 王荣
	 */
	public void updateAttendOvertimeApplication(Map<String, Object> map) {
		String status = map.get("status").toString();//审批操作
		String id = map.get("id").toString();
		String approverId = map.get("approverId")==null?null:map.get("approverId").toString();//表示下一审核人的id
		String reason = map.get("reason").toString();
		String pageType = RedirectUrlUtil.ATTEND_OVERTIME_APPROVAL_DETAIL_URL+id;
		//修改审批流程状态
		if(!"3".equals(status)) {
			dingTalkMapper.updateAttendProcess(map);
		}else {//撤销 添加撤销流程
			dingTalkMapper.insertAttendProcess(map);
		}
		if("4".equals(status)) {//转交 添加转交流程
			dingTalkMapper.insertAttendProcess(map);
		}
		//Timer timer = new Timer();
		//没有下一个审批人，表示审批完成，发送审批处理通知
		if(approverId==null || "".equals(approverId)) {
			//修改attend_approval_all表的状态
			dingTalkMapper.updateAttendApprovalState(map);
			//修改attend_approval_overtime表的状态
			dingTalkMapper.updateAttendOvertimeApproval(map);
			
			if("1".equals(status)) {
				//审核通过 则插入打卡时间 重新计算工资
				AttendApplicationDetailInfoPojo pojo = dingTalkMapper.getApplicationDetailInfo(map);
				
				
				Map<String, Object> fillCardMap = new HashMap<>();
				fillCardMap.put("deviceNo", "JBdeviceNo");
				fillCardMap.put("loginUserId", pojo.getCreaterId());
				fillCardMap.put("verify_mode", "30");//加班
				fillCardMap.put("io_mode", "0");
				String ioTimeStart = pojo.getApprovalContentMap().get("startTime").toString();
				String ioTimeEnd = pojo.getApprovalContentMap().get("endTime").toString();
				fillCardMap.put("io_time_start", ioTimeStart);
				fillCardMap.put("guid_start", GUID.getGuid());
				fillCardMap.put("io_time_end", ioTimeEnd);
				fillCardMap.put("guid_end", GUID.getGuid());
				CompanyBean companyBean = companyMapper.getCompany(map);
				if(companyBean!=null && companyBean.getOverTimeAddTblLog().intValue() == 1){
					dingTalkMapper.saveOvertime(fillCardMap);//插入到加班补卡
				}
				//重新计算工资
				String calculateDate = ioTimeStart.substring(0,10);
				attendanceService.updateDailySalaryRecord(calculateDate,calculateDate,map.get("loginCompany").toString(),pojo.getCreaterId());
			}
			
			//发送审批处理通知
			/*timer.schedule(new TimerTask() {
				@Override
				public void run() {*/
					AttendanceApprovalInfoPojo approvalBean = dingTalkMapper.getOvertimeApprovalDetail(id);
					//重新计算相关日期的每日工资
					if("1".equals(status) || "3".equals(status)) {
						attendanceService.updateDailySalaryRecord(approvalBean.getStartTime(), approvalBean.getEndTime(), approvalBean.getCompany(), approvalBean.getCreaterId());
					}
					//发送审批处理消息
					List<Map<String,Object>> processList = approvalBean.getProcessList();
					String approverName = "";//协助人的姓名
					if(processList!=null && processList.size()>0) {
						for(Map<String,Object> a :processList) {
							approverName+=a.get("approverName")+"，";
						}
					}
					approverName = approverName.substring(0, approverName.length()-1);
					//发送给提交人
					sendApplyStatusTips("您的加班申请已处理，请知晓",approvalBean.getCreaterId().toString(),status,approverName,pageType);
					List<Map<String,Object>> copyforList = approvalBean.getCopyforList();
					for(Map<String,Object> copyforMap : copyforList) {
						//发送给抄送人
						sendApplyStatusTips(approvalBean.getCreaterName()+"的加班审批已处理，请知晓",copyforMap.get("copyforId").toString(),status,approverName,pageType);
					}
				//}
			//}, 100);
		}else {//审批未完成，还有下一个审批人，发送待审核任务
			/*timer.schedule(new TimerTask() {
				@Override
				public void run() {*/
					AttendApplicationDetailInfoPojo approvalBean = dingTalkMapper.getApplicationDetailInfo(map);
					//发送待审核消息
					sendWatiApprovalTips(approverId, "3",approvalBean.getCreaterName(), approvalBean.getCreaterPhone(), reason, "",pageType);
			/*	}
			}, 100);*/
		}
	}
	/**
	 * 操作加班审批单-批量
	 * @param map
	 * @author 王荣
	 */
	public void updateAttendOvertimeApplicationBatch(Map<String, Object> requestParam) {
		// TODO Auto-generated method stub
		Gson gson = new Gson();
		net.sf.json.JSONArray jsonarray = net.sf.json.JSONArray.fromObject((String) requestParam.get("data"));
		for(Object obj : jsonarray) {
			Map<String, Object> newMap = (Map<String , Object>)obj;
			newMap.put("loginCompany", requestParam.get("loginCompany"));
			newMap.put("loginUserName", requestParam.get("loginUserName"));
			newMap.put("loginUserId", requestParam.get("loginUserId"));
			newMap.put("loginUserDeptId", requestParam.get("loginUserDeptId"));
			newMap.put("loginUserPhone", requestParam.get("loginUserPhone"));
			newMap.put("loginUserOpenId", requestParam.get("loginUserOpenId"));
			newMap.put("loginCompanyId", requestParam.get("loginCompanyId"));
			newMap.put("loginCompanyType", requestParam.get("loginCompanyType"));
			System.out.println(newMap);
			updateAttendOvertimeApplication(newMap);
		}
	}
	
	/**
	 * 外出打卡
	 * @param requestMap
	 * @return
	 */
	public String dkOutSide(Map<String, Object> requestMap,List<PersonBean> personBeans) {
		// TODO Auto-generated method stub
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		if(personBeans.size()>0) {
			if(personBeans.get(0).getDeviceList().size()==0) {
				throw new ServiceException("打卡失败!您尚未配置打卡机,请前往职员表配置");
			}
			String deviceNo = personBeans.get(0).getDeviceList().get(0).get("deviceNo").toString();
			if(deviceNo.length()>0) {
				//保存打卡数据
				requestMap.put("deviceNo", deviceNo);
				requestMap.put("verify_mode", "10");//外出
				requestMap.put("io_mode", "0");
				com.ray.util.dk.GUID guid = com.ray.util.dk.GUID.getInstance();
				requestMap.put("guid", guid.getGuid());
				dingTalkMapper.saveDataOutSide(requestMap);
				//发送微信推送
				requestMap.put("userId", requestMap.get("loginUserId"));
				requestMap.put("userCheckTime", sdf.format(new Date()));
				this.sendClockMessage(requestMap);
			}else {
				throw new ServiceException("打卡失败!您尚未配置打卡机,请前往职员表配置");
			}
		}else {
			throw new ServiceException("打卡失败!您尚未配置打卡机,请前往职员表配置");
		}
		return "打卡成功";
	}
	
	/**
	 * 添加报销申请审批  type 4
	 * @param map
	 * @author 王荣
	 */
	public String insertReimburse(Map<String,Object> map) {
		Gson gson = new Gson();
		ReimburseBean reimburseBean = gson.fromJson((String) map.get("data"), ReimburseBean.class);
		List<String> auditorList = reimburseBean.getAuditorList();
		List<String> copyPersonList = reimburseBean.getCopyPersonList();
		map.put("id", reimburseBean.getId());
		map.put("approvalNo", dingTalkMapper.getApprovalNo("BX"));//报销
		map.put("reimburseList", reimburseBean.getReimburseInfoBeans());
		map.put("auditorList", auditorList);
		map.put("copyPersonList", copyPersonList);
		
		dingTalkMapper.insertReimburse(map);
		
		String firstApproverId = auditorList.get(0);
		String loginUserName = map.get("loginUserName").toString();
		String loginUserPhone = map.get("loginUserPhone").toString();
		String pageType = RedirectUrlUtil.Reimbursement_APPROVAL_DETAIL_URL+map.get("id");
		//发送消息  异步执行
		sendWatiApprovalTips(firstApproverId, "4",loginUserName, loginUserPhone, "", "",pageType);
		/*Object context = "上下文信息";
		new CallBackTask(new CallBackBody() {
            @Override
			public void execute(Object context) throws Exception {
                System.out.println("\n正在执行耗时操作...");
                
        		sendWatiApprovalTips(firstApproverId, "4",loginUserName, loginUserPhone, "", "",pageType);
                System.out.println("\n执行完成！");
            }
            public void onSuccess(Object context) {
                System.out.println("\n成功后的回调函数...");
            }
            public void onFailure(Object context) {
                System.out.println("\n失败后的回调函数...");
            }
        }).start(context);*/
		return map.get("id").toString();
	}
	
	/**  
	 * 操作报销审核
	 * @param map  
	 * @author 王荣
	 */ 
	public void updateAttendApprovalForReimburse(Map<String,Object> map) {
		String status = map.get("status").toString();//审批操作
		String id = map.get("id").toString();
		String approverId = map.get("approverId")==null?null:map.get("approverId").toString();//表示下一审核人的id
		String reason = map.get("reason").toString();
		String type = map.get("type").toString();
		String price = map.get("price").toString();
		String pageType = RedirectUrlUtil.Reimbursement_APPROVAL_DETAIL_URL+id;
		//修改审批流程状态
		if(!"3".equals(status)) {
			dingTalkMapper.updateAttendProcess(map);
		}else {//撤销 添加撤销流程
			dingTalkMapper.insertAttendProcess(map);
		}
		if("4".equals(status)) {//转交 添加转交流程
			dingTalkMapper.insertAttendProcess(map);
		}
		//Timer timer = new Timer();
		//没有下一个审批人，表示审批完成，发送审批处理通知
		if(approverId==null || "".equals(approverId)) {
			//修改attend_approval_all表的状态
			dingTalkMapper.updateAttendApprovalState(map);
			//修改reimburse表的状态
			dingTalkMapper.updateReimburseApproval(map);
			//发送审批处理通知
			/*timer.schedule(new TimerTask() {
				@Override
				public void run() {*/
					AttendApplicationDetailInfoPojo approvalBean = dingTalkMapper.getApplicationDetailInfo(map);
					//发送审批处理消息
					List<Map<String,Object>> processList = approvalBean.getProcessList();
					String approverName = "";//协助人的姓名
					if(processList!=null && processList.size()>0) {
						for(Map<String,Object> a :processList) {
							approverName+=a.get("approverName")+"，";
						}
					}
					approverName = approverName.substring(0, approverName.length()-1);
					//发送给提交人
					sendApplyStatusTips("您的报销申请已处理，请知晓",approvalBean.getCreaterId().toString(),status,approverName,pageType);
					List<Map<String,Object>> copyforList = approvalBean.getCopyforList();
					for(Map<String,Object> copyforMap : copyforList) {
						//发送给抄送人
						sendApplyStatusTips(approvalBean.getCreaterName()+"的报销审批已处理，请知晓",copyforMap.get("copyforId").toString(),status,approverName,pageType);
					}
				/*}
			}, 100);*/
		}else {//审批未完成，还有下一个审批人，发送待审核任务
			/*timer.schedule(new TimerTask() {
				@Override
				public void run() {*/
					AttendApplicationDetailInfoPojo approvalBean = dingTalkMapper.getApplicationDetailInfo(map);
					//发送待审核消息
					sendWatiApprovalTips(approverId, "4",approvalBean.getCreaterName(), approvalBean.getCreaterPhone(), type+"-"+reason+"-"+price+"(元)", "",pageType);
				/*}
			}, 100);*/
		}
	}
	
	/**
	 * 查询报销审批记录
	 * @param map
	 * @author 王荣
	 */
	public DatatablesViewPageBean queryReimburseRecord(Map<String, Object> map){
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		int count = 0;
		DatatablesViewPageBean dvpb = new DatatablesViewPageBean<>();
		Map<String, Object> countMap = dingTalkMapper.queryReimburseRecordCount(map);
		count=(int)countMap.get("count");
		net.sf.json.JSONObject object = new net.sf.json.JSONObject();
		object.put("sumPrice", countMap.get("sumPrice").toString());
		dvpb.setMsg(object.toString());
		dvpb.setReturnData(count>0?dingTalkMapper.queryReimburseRecord(map):null);
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	/**
	 * 提交行政处罚 type=5
	 * @param map
	 * @return
	 */
	public String insertAdministrativePenalty(Map<String, Object> map) {
		Gson gson = new Gson();
		AdministrativePenaltyBean administrativePenaltyBean = gson.fromJson((String) map.get("data"), AdministrativePenaltyBean.class);
		List<String> auditorList = administrativePenaltyBean.getAuditorList();
		List<String> copyPersonList = administrativePenaltyBean.getCopyPersonList();
		map.put("id", administrativePenaltyBean.getId());
		map.put("approvalNo", dingTalkMapper.getApprovalNo("CF"));//报销
		map.put("reimburseList", administrativePenaltyBean.getReimburseInfoBeans());
		map.put("auditorList", auditorList);
		map.put("copyPersonList", copyPersonList);
		
		dingTalkMapper.insertAdministrativePenalty(map);
		
		String firstApproverId = auditorList.get(0);
		String loginUserName = map.get("loginUserName").toString();
		String loginUserPhone = map.get("loginUserPhone").toString();
		String penaltyType = map.get("penaltyType").toString();
		
		
		String pageType ="";
        switch(penaltyType) {
			case "5":pageType = RedirectUrlUtil.AdministrativePenalty_CF_APPROVAL_DETAIL_URL+map.get("id");break;//处罚
			case "6":pageType = RedirectUrlUtil.AdministrativePenalty_JL_APPROVAL_DETAIL_URL+map.get("id");break;//奖励
        }
		sendWatiApprovalTips(firstApproverId, penaltyType,loginUserName, loginUserPhone, "", "",pageType);
		//发送消息  异步执行
		/*Object context = "上下文信息";
		new CallBackTask(new CallBackBody() {
            @Override
			public void execute(Object context) throws Exception {
                System.out.println("\n正在执行耗时操作...");
                String pageType ="";
                switch(penaltyType) {
    				case "5":pageType = RedirectUrlUtil.AdministrativePenalty_CF_APPROVAL_DETAIL_URL+map.get("id");break;//处罚
    				case "6":pageType = RedirectUrlUtil.AdministrativePenalty_JL_APPROVAL_DETAIL_URL+map.get("id");break;//奖励
                }
        		sendWatiApprovalTips(firstApproverId, penaltyType,loginUserName, loginUserPhone, "", "",pageType);
                System.out.println("\n执行完成！");
            }
            public void onSuccess(Object context) {
                System.out.println("\n成功后的回调函数...");
            }
            public void onFailure(Object context) {
                System.out.println("\n失败后的回调函数...");
            }
        }).start(context);*/
		return map.get("id").toString();
	}
	
	/**  
	 * 操作行政处罚审核
	 * @param map  
	 * @author 王荣
	 */ 
	public void updateAttendApprovalForAdministrativePenalty(Map<String,Object> map) {
		String status = map.get("status").toString();//审批操作
		String id = map.get("id").toString();
		String approverId = map.get("approverId")==null?null:map.get("approverId").toString();//表示下一审核人的id
		String reason = map.get("reason").toString();
		String type = map.get("type").toString();
		String price = map.get("price").toString();
		String penaltyType = map.get("penaltyType").toString();
		//修改审批流程状态
		if(!"3".equals(status)) {
			dingTalkMapper.updateAttendProcess(map);
		}else {//撤销 添加撤销流程
			dingTalkMapper.insertAttendProcess(map);
		}
		if("4".equals(status)) {//转交 添加转交流程
			dingTalkMapper.insertAttendProcess(map);
		}
		//Timer timer = new Timer();
		
		//没有下一个审批人，表示审批完成，发送审批处理通知
		if(approverId==null || "".equals(approverId)) {
			//修改attend_approval_all表的状态
			dingTalkMapper.updateAttendApprovalState(map);
			//修改administrative_penalty表的状态
			dingTalkMapper.updateAdministrativePenaltyApproval(map);
			//发送审批处理通知
			/*timer.schedule(new TimerTask() {
				@Override
				public void run() {*/
					AttendApplicationDetailInfoPojo approvalBean = dingTalkMapper.getApplicationDetailInfo(map);
					//发送审批处理消息
					List<Map<String,Object>> processList = approvalBean.getProcessList();
					String approverName = "";//协助人的姓名
					if(processList!=null && processList.size()>0) {
						for(Map<String,Object> a :processList) {
							approverName+=a.get("approverName")+"，";
						}
					}
					approverName = approverName.substring(0, approverName.length()-1);
					//发送给提交人
					String pageType = "";
					String msgContent="行政奖罚申请已处理，请知晓";
					switch(penaltyType) {
						case "5":pageType = RedirectUrlUtil.AdministrativePenalty_CF_APPROVAL_DETAIL_URL+id;msgContent="行政罚款申请已处理，请知晓";break;//处罚
						case "6":pageType = RedirectUrlUtil.AdministrativePenalty_JL_APPROVAL_DETAIL_URL+id;msgContent="行政奖励申请已处理，请知晓";break;//奖励
					}
					sendApplyStatusTips("您的"+msgContent,approvalBean.getCreaterId().toString(),status,approverName,pageType);
					List<Map<String,Object>> copyforList = approvalBean.getCopyforList();
					for(Map<String,Object> copyforMap : copyforList) {
						//发送给抄送人
						sendApplyStatusTips(approvalBean.getCreaterName()+msgContent,copyforMap.get("copyforId").toString(),status,approverName,pageType);
					}
				/*}
			}, 100);*/
		}else {//审批未完成，还有下一个审批人，发送待审核任务
			/*timer.schedule(new TimerTask() {
				@Override
				public void run() {*/
					AttendApplicationDetailInfoPojo approvalBean = dingTalkMapper.getApplicationDetailInfo(map);
					String pageType = "";
					switch(penaltyType) {
						case "5":pageType = RedirectUrlUtil.AdministrativePenalty_CF_APPROVAL_DETAIL_URL+id;break;//处罚
						case "6":pageType = RedirectUrlUtil.AdministrativePenalty_JL_APPROVAL_DETAIL_URL+id;break;//奖励
					}
					//发送待审核消息
					sendWatiApprovalTips(approverId, penaltyType,approvalBean.getCreaterName(), approvalBean.getCreaterPhone(), type+"-"+reason+"-"+price+"(元)", "",pageType);
				/*}
			}, 100);*/
		}
	}
	/**
	 * 
	 * @param map
	 * @return
	 */
	public DatatablesViewPageBean<OvertimeApplicationPojo> queryAdministrativePenaltyRecord(Map<String, Object> map) {
		map.put("deptIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("deptIds", k -> "[]").toString()));
        map.put("workshopIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("workshopIds", k -> "[]").toString()));
        map.put("userIdList", DingTalkUtil.parseJsonArrayStrToListInteger(map.computeIfAbsent("userIds", k -> "[]").toString()));
		int count = 0;
		DatatablesViewPageBean dvpb = new DatatablesViewPageBean<>();
		count = dingTalkMapper.queryAdministrativePenaltyCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.queryAdministrativePenaltyRecord(map):null);
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	
	public void insertAttendClassTail(List<AttendClassTailBean> beans,Map<String, Object> map) {
		// TODO Auto-generated method stub
		dingTalkMapper.insertAttendClassTail(beans,map);
	}
	
	public List<AttendClassTailBean> getAttendClassTail(Map<String, Object> map) {
		// TODO Auto-generated method stub
		return dingTalkMapper.getAttendClassTail(map);
	}
	
	public DatatablesViewPageBean<AttendApprovalProcessUniteBean> queryApprovalProcessSetForUnite(Map<String, Object> map) {
		// TODO Auto-generated method stub
		DatatablesViewPageBean dvpb = new DatatablesViewPageBean<>();
		int count = dingTalkMapper.queryApprovalProcessSetForUniteCount(map);
		dvpb.setReturnData(count>0?dingTalkMapper.queryApprovalProcessSetForUnite(map):null);
		dvpb.setiTotalDisplayRecords(count);
		dvpb.setiTotalRecords(count);
		return dvpb;
	}
	public void insertApprovalProcessSetForUnite(Map<String, Object> map) {
		// TODO Auto-generated method stub
		dingTalkMapper.insertApprovalProcessSetForUnite(map);
	}
	
	public Map getCodeAreaByCodeIdForRuianCode(Map<String, Object> map) {
		Map<String , Object> retMap = new HashMap<>();
		String codeArea = "";
		try {
            URL url = new URL("http://dx.raga.gov.cn:8921/mst/kk.jsp?cr=0&id="+map.get("codeId"));
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            conn.setRequestMethod("GET");
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            /*if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }*/
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            
            Document doc = Jsoup.parse(buffer.toString());
            Elements rows = doc.select("div[class=weui-form__text-area]");
            if (rows.size() == 1) {
            	System.out.println("--------------------------- 查询结果 ---------------------------");
                Element row = rows.get(0);
                codeArea = row.select("div").get(0).text();
                String reg = "[^\u4e00-\u9fa5]";
                codeArea = codeArea.replaceAll(reg, " ").replaceAll("你正在", "").replaceAll("进", "").trim();
            }else {
            	System.out.println("没有结果");
            }
            retMap.put("data", codeArea);
        } catch (ConnectException ce) {
            System.out.println("连接超时：{}");
        } catch (Exception e) {
            System.out.println("https请求异常：{}");
        }
        return retMap;
	}
}
